卡片与你的智能体并肩工作
卡片能看到画布上有哪些智能体、它们在做什么。用箭头连上一个智能体,卡片就能响应它的每一轮、为它提供工具,或交给它下一个任务。
智能体完成时做出反应
卡片订阅智能体事件:状态变化、一轮的开始与结束、新的输出。这里,每当相连的智能体结束一轮,测试雷达就重新跑一遍测试。
card.agents.onTurn(({ agentId, phase }) => { if (phase === 'end') runTests()})卡片沿箭头对话,传的是类型化数据
卡片为自己的输入和输出声明类型:文本、Markdown、任务、表格、事件——或者带结构定义的自定义类型。画一条箭头,数据就开始流动。应用会在两端校验,并在内置卡片需要别的格式时自动转换。
打开或关闭箭头,然后运行测试。
内置卡片也参与其中
笔记追加 Markdown,清单添加任务,看板添加任务卡,智能体接收提示词,终端执行命令。你的卡片用同一种方式与它们对话。
靠类型,不靠猜
通用类型(ns:text、ns:markdown、ns:tasks、ns:table、ns:event…)或带 JSON 结构定义的 your-card/your-type。每个值在送达前都由应用校验。
不只是数据流,还能请求
输入可以应答:ports.request 向相连的卡片提问并等待回复。保留型输出会在你连上卡片的那一刻把最新值交给它。
社区代码,严格约束
安装之前,你会看到是谁做的、来自哪里、哪个提交,以及用大白话写明它能做什么。之后,应用严格按此执行。
安装 测试雷达?
社区代码,非 NeuroSquad 制作或审核。只安装你信任的人的卡片。
卡片内部的一切都属于卡片本身。NeuroSquad 绝不会在那里索要密码或密钥。
此卡片将能够
在与其相连的终端中运行命令
高风险在用箭头与它相连的终端卡片中输入并运行命令——任何你自己能运行的命令。
读取和修改与其相连的卡片
中用箭头与它相连的笔记、清单、任务看板和便签。
为你连接的智能体提供工具:run_tests
通过箭头交换数据:1 个输入,1 个输出
封闭在自己的框架里
每张卡片都运行在拥有独立源的沙箱框架中。无法访问应用、Node、其他卡片,也无法访问超出授权的文件。
永远不离开画布
没有弹窗、没有新窗口、没有覆盖在应用上的对话框、没有下载。卡片只在自己的框内绘制,并随画布缩放。
只有你授予的权限
每次调用都由应用对照授权检查。可选权限稍后在卡片上请求,任何权限都可以撤销。
箭头即同意
只有你在两者之间画了箭头,卡片才能触及另一张卡片、智能体或终端——而且还需要对应的权限。
网络走代理
只能访问卡片声明过的主机。你输入的密钥由应用填入请求;卡片永远看不到。
锁定提交,从不自动更新
安装锁定在某个提交上。新版本会展示改了什么、增加了哪些权限,并等待你点击。
一张完整的卡片,一个短文件
这是一张完整的卡片。它在相连的终端里运行测试,把失败项沿箭头发出,为智能体提供 run_tests 工具,并在相连的智能体结束一轮时重新运行。旁边的清单文件说明它需要什么。
1import { connect } from '@neurosquad/card-sdk'2 3const card = await connect()4 5/** Runs the suite in the terminal this card is wired to and sends out what broke. */6async function runTests(filter = ''): Promise<string[]> {7 const shell = card.ports.peers.find((peer) => peer.kind === 'terminal')8 if (!shell) throw new Error('Draw an arrow from this card to a terminal')9 10 await card.setStatus('Running tests…', { busy: true })11 const { output } = await card.terminals.run(shell.cardId, `npm test -- ${filter}`)12 const failed = output.split('\n').filter((line) => line.includes('✗'))13 14 const tone = failed.length ? 'danger' : 'success'15 await card.setStatus(failed.length ? `${failed.length} failed` : 'Passing', { tone })16 // ns:tasks: a checklist adds them, a note gets a Markdown list17 await card.ports.emit('failures', failed.map((text) => ({ text, status: 'error' })))18 return failed19}20 21// Connected agents see this as test_radar_run_tests over MCP22card.tools.handle<{ filter?: string }>('run_tests', async ({ filter }, call) => {23 call.progress('running…')24 const failed = await runTests(filter)25 return failed.length ? failed.join('\n') : 'All tests passed'26})27 28// A connected agent finished its turn: check its work29card.agents.onTurn(({ agentId, phase }) => {30 const wired = card.ports.peers.some((peer) => peer.cardId === agentId)31 if (phase === 'end' && wired) runTests().catch((error) => card.log.error(error))32})33 34// Anything on the "run" input (a button, a schedule) starts a run35card.ports.onMessage(() => void runTests(), { input: 'run' })一个 connect()
它等待与应用握手,返回一个类型化的客户端:每个方法、事件和数据都有类型。
清单文件就是契约
权限、端口、工具和设置都预先声明——安装对话框展示的正是这些。
不开应用也能测试
createMockHost() 让卡片运行在内存中的宿主上,它按应用的顺序执行应用自己的检查。
客户端能做什么
card.setStatus()标题、状态、徽标、概览磁贴、提醒card.ui提示、确认和卡片菜单card.storage按卡片和按包的存储card.settings由应用绘制的设置表单,包括密钥card.agents列出、关注、读取智能体并向其发送提示词card.terminals在相连的终端里运行命令card.ports沿箭头的类型化输入和输出card.tools为相连智能体提供的工具card.net经应用代理的 HTTP 请求,支持流式card.fs工作区文件夹中的文件card.lifecycle可见性、暂停、尺寸变化createTranslator()英语、俄语和中文,实时切换
三条命令,做出第一张卡片
需要 Node.js 18.17 或更高版本,以及在「设置 → 自定义卡片」中开启了开发者模式的 NeuroSquad。
- 1
创建
$npx @neurosquad/card-sdk create my-card一个能跑的起步模板:实时智能体状态、会保存的草稿、一个端口和一个工具。加上
--template react即使用 React 和 Vite。 - 2
实时运行
$cd my-card && npx @neurosquad/card-sdk dev在你确认后把文件夹链接到应用,每次保存都重新加载卡片,并输出它的日志。
- 3
检查
$npx @neurosquad/card-sdk validate运行应用自己的校验器,并打印用户将看到的安装对话框。
然后分享出去
把文件夹推送到 GitHub。任何人在「设置 → 自定义卡片」中粘贴 owner/repo 即可安装。更新从不自动进行:每个新提交都会连同权限变化一起展示,由你点击后才应用。
想要什么样子都行
标题栏、边框和菜单属于应用。里面的一切都属于你:任意 HTML、CSS、画布或 3D。想要原生外观,还有一套可选样式,跟随应用的实时主题。