加密在两端完成Encryption happens at both ends
手机和电脑配对时,直接在两台设备之间交换钥匙。我们的服务器不参与,也拿不到钥匙。When you pair, your phone and your computer exchange keys directly. Our servers aren't part of that exchange and never get the keys.
你和 Agent 说的话、它在你电脑上处理的东西,我们都看不到。唯一的例外是网页版:手机上的网页是我们的服务器发下来的,万一我们(或黑进我们服务器的人)改了网页,就能看到你手机屏幕上的内容。这个口子要等原生 App 出来才能堵上。下面先用大白话回答常见问题,再列出哪些已经上线、哪些还没做,最后是给想核对细节的人看的技术说明。What you and your Agent say to each other, and what it works on inside your computer, is invisible to us. The one exception is the web app: the phone web page comes from our servers, so if we (or someone who broke into our servers) changed that page, it could read what's on your phone screen. Closing that gap takes a native app. Below: plain answers to common questions first, then what's live and what isn't, then the technical details for anyone who wants to check.
agentj config history off。What the AI remembers about how you work (Memory), your chat and activity history, and the scheduled tasks you've set up. They live only on your computer and travel encrypted when your phone reads them. Don't want the chat history kept there? Run agentj config history off on the computer.agentj report-hostname off,也可以让你的 AI 替你运行。Your Agent's name and your computer's name (the one set in its operating system). To stop sending the computer's name, run agentj report-hostname off on the computer, or ask your AI to run it for you.agentj doctor 的检查结果的话,这个我们也看得到。你的对话、文件和密钥,客服看不到。升级失败时,电脑也会自己发一份:失败的步骤、原因和安装命令最后几行,同样先去掉这些信息。不想自动发,就让 Agent 关掉 updates.report_failures。What your Agent asks our support desk (an error, a hint it doesn't understand, a workflow question). Before it leaves, your computer removes keys, email addresses, phone numbers, user names and paths; our server scans it again. Our support Agent and we can read it in full, plus the agentj doctor check results if the Agent attaches them. The support desk never sees your conversations, files or keys. When an upgrade fails, your computer sends this by itself as well: the failed step, the reason and the installer's last lines, cleaned the same way first. Ask your Agent to turn off updates.report_failures if you don't want that.agentj update auto off。GitHub (a website that hosts code). Once a day your computer checks GitHub for a new version, so GitHub sees your computer's IP address and the time. To turn the check off, run agentj update auto off on the computer.手机和电脑配对时,直接在两台设备之间交换钥匙。我们的服务器不参与,也拿不到钥匙。When you pair, your phone and your computer exchange keys directly. Our servers aren't part of that exchange and never get the keys.
服务器上只有加密后的乱码,没有钥匙解不开。它把乱码从一端送到另一端,不存内容,不记日志。All it holds is scrambled data it has no key for. It passes that from one end to the other, stores nothing and keeps no logs.
已绑定账号且在线的电脑,可以在席位卡用通行密钥确认后扫码。电脑验证签名、一次性、五分钟有效的请求。二维码加密给你的浏览器,我们不保存明文。账户页配对信任签名控制平面:签名服务被攻破可能增加遥控器。可用 agentj remote-pair off 关闭;本机配对仍用六位码和本机口令。For an account-bound online computer, confirm with your account passkey and scan the code on its seat card. The computer verifies a signed, one-use, five-minute request. QR material is encrypted to your browser; we do not store its plaintext. Account-page pairing trusts our signing control plane: compromise of that signer could add a phone. Disable it with agentj remote-pair off. Local pairing still uses a six-digit code and a local passphrase.
Agent 用你的电脑账号运行,你电脑上的文件它都能读写,所以能照常整理你的订单和报表。它碰不到的是 Agent J 自己的东西:配对钥匙、手机名单和遥控器配对密码。所以它没法自己批准自己,也没法偷偷加手机。Your Agent runs under your computer account and can read and write your files, so it can sort your orders and reports as usual. What it can't reach is Agent J's own material: the pairing keys, the list of phones and your passphrase. So it can't approve its own requests or slip in a phone.
Agent J 自己不另外上锁。Agent 能做什么、什么时候要先问你,按你的 AI 编程工具(Claude Code、Codex 或 OpenCode)自己的权限规则来;它要问权限时,问题会送到你的手机上,Agent J 绝不替你回答。你在工具里禁止的事,手机上也批不了。Agent J adds no locks of its own. What the Agent may do, and when it must ask you first, follows the permission rules of your AI coding tool (Claude Code, Codex or OpenCode); when the tool asks for permission, the question comes to your phone, and Agent J never answers it for you. Anything you've forbidden in the tool can't be approved from the phone either.
Agent J 只守住数据安全的底线:密钥不进对话、日志、git 和不加密的通道(要管理员密码或 API key 时,在你手机上的卡片里输入,Agent 看不到);新手机和每一次批准都要你手机的签名;不碰别人的数据。另外有一个可选的「高风险提醒」,默认关闭,在手机「设置」里打开后,花钱(付款、下单)、删除、对外发送(发邮件和消息、上传、调用外部接口写数据)、改密码或密钥、改价格(店铺商品价格、优惠码、广告预算)这五类操作,每一次都单独在手机上问你。手机上的「记录」页能看到每一次请求和你的决定。Agent 发邮件:发给你自己、或者发给邮件白名单里的人,直接发;发给别人,每一封都要你在手机上确认。Agent J only keeps the data-safety floor: keys never go into the chat, logs, git or an unencrypted channel (an admin password or API key is entered in a card on your phone, out of the Agent's sight); new phones and every approval need your phone's signature; nobody else's data is touched. On top of that there are optional "High-risk warnings", off by default; turn them on in the phone's Settings and five kinds of action ask you on the phone every single time: spending money (payments, orders), deleting, sending things out (email and messages, uploads, calling outside APIs that write data), changing passwords or keys and changing prices (product prices, promo codes, ad budgets). The phone's Activity page shows every request and what you decided. E-mail from the Agent: to yourself or to people on your e-mail allowlist it goes straight out; to anyone else, every mail needs your confirmation on the phone.
打开高风险提醒后要知道的局限:程序看的是命令本身写了什么。比如改亚马逊广告出价,如果 Agent 直接调用接口,会被当成「对外发送」拦下来问你。但如果它运行的是一个脚本文件(事先写好的一段程序),程序看不到脚本里面会做什么,不会把它算进这五类;这时问不问你,看你的 AI 助手自己的设置。卡片上看到它要运行某个脚本,而你不清楚这个脚本干什么,就点拒绝,或者先让 AI 用大白话解释这个脚本会做什么。One limit to know when high-risk warnings are on: the program judges what the command itself says. If the Agent changes an Amazon ad bid by calling the API directly, that's caught as "sending things out" and asks you. But if it runs a script file (a program written beforehand), the program can't see what the script will do and doesn't count it among the five; whether you're asked then depends on your AI assistant's own settings. If a card shows it wants to run a script you don't understand, deny it, or first ask the AI to explain in plain words what the script does.
出了事谁负责:Agent 是你的 AI 助手,用你的账号做事,有风险的操作由你批准。我们的责任范围写在服务条款里(Beta 草稿)。Who's responsible if something goes wrong: the Agent is your AI assistant acting on your account, and risky actions run only with your approval. Our own responsibilities are set out in the terms (Beta draft).
Agent 不会用浏览器登录你的卖家后台,我们也从不要你的店铺密码。我们准备了五个现成的电商工作流模板:跨平台经营日报、广告复盘、Listing 撰写与巡检、客服回复草稿、选品调研周报。它们包含在席位费里,不另收费。装好以后你在手机上说「帮我设计工作流」,向导会问你要用哪些;模板装上时是关着的,要不要按时运行由你决定。这些模板读的是你下载到电脑上的报表,或者你自己给它接好的官方接口(比如亚马逊 SP-API、Shopify Admin API)。The Agent never signs in to your Seller Central or store admin through a browser, and we never ask for your store password. We've prepared five ready-made e-commerce workflow templates: a daily business report, an ads review, listing drafting and checks, draft replies to customers, and weekly product research. They're included in the seat price at no extra charge. Once you're set up, say "帮我设计工作流" (help me design my workflows) on your phone and the wizard asks which ones you want; a template is switched off when it's added, and you decide whether it runs on schedule. They work from reports you've downloaded to your computer, or from official APIs you've connected yourself (such as Amazon SP-API or the Shopify Admin API).
接口的 key 由你自己在电脑上设置,我们看不到。但要知道:key 和报表放在你电脑上,Agent 读得到;它处理时,相关内容会发给你选的 AI 公司。You set up any API keys on your own computer, and we can't see them. But keep in mind: keys and reports on your computer are readable by the Agent, and what it works on is sent to the AI company you chose.
平台规定:亚马逊、Shopify 对第三方工具和买家数据有各自的规定。哪些数据可以交给 AI 处理,要你按平台的规定自己判断;我们没有替你做合规审核。Platform rules: Amazon and Shopify each have their own rules about third-party tools and buyer data. Which data you let an AI process is your call under those rules; we haven't reviewed compliance for you.
已上线Live now
agentj 程序里。你的 Agent 安装前在你的电脑上核对签名,对不上就不装。Certified skills and workflows on the Plaza carry our signature. The key we sign with stays on our own machine and is never put on a server; the public key for checking is built into agentj. Your Agent checks the signature on your computer before installing, and refuses if it doesn't match.还没做(Beta 还差什么)Not done yet (what the Beta still lacks)
下面这部分写给想核对细节的人,会用到一些技术名词,每个都附一句解释。This part is for people who want to check the details. It uses some technical terms, each with a one-line explanation.
「我们看不到你的数据」是这个产品的红线。这一部分逐条写清楚它靠什么成立、Beta 现在做到了哪一步、我们仍然看得到什么。用到的技术名词,第一次出现时附一句解释。
先说结论:你现在买到的 Beta,手机和电脑之间的聊天是端到端加密的,所有用户都一样,没有不加密的备用通道。(端到端加密:内容在一端加密、到另一端才解开,中间经过的服务器只拿到乱码。)现在加密的是文字:你的消息、Agent 的回复、状态和审批卡片;图片、文件和语音还不能经手机发送。
但下面五项保证,你今天还都没法自己独立核对:源码只公开了一部分,目前靠的是我们自己的自动化测试,加上两个 AI 模型交叉做的安全检查,这不是第三方审计(检查提出的问题已经修完,或者列成了已知风险)。账户页可经通行密钥批准主人操作,配对材料只以密文短时中转(见下文)。手机上的网页由我们下发,网页版的目标是「改了会被发现」,Beta 还没做到;无论如何网页版都做不到「我们看不到」,真正做到的入口要等原生 App。
正常协议下,聊天内容在手机和电脑之间加密,服务器只转发密文。账户页的签名控制平面被信任可以批准新增设备、恢复和任务启用:如果它被攻破,可能授予攻击者新的访问权限。因此不能承诺云端被攻破后仍无法添加设备。关闭 agentj remote-pair off 可拒绝账户页批准路径;本机配对和遥控器配对密码的散列保存在电脑上。主人在账户页用这个密码代替通行密钥时(0.20.3),浏览器先用电脑为这一次临时给出的一次性公钥把它加密(X25519 + AES-GCM),只有电脑能解开、核对(scrypt,连续错 5 次锁定);这把钥匙只用一次、从不离开电脑内存,后端只转发、短暂保存密文——从我们服务器拿走的副本既解不开,也没法重放。浏览器页面本身由我们下发,仍有下文说明的风险。
这要五件事同时成立,缺一条就不算:
状态图例:绿 · 已上线,可以自己核对 黄 · 设计完成,或已经上线但还不能由你独立核对 红 · 还没做
| # | 保证 | Beta 现在 |
|---|---|---|
| 1 | 手机和电脑之间端到端加密,我们不持有会话密钥 | 文字、文件和语音已上线,还不能独立核对 |
| 2 | 转发服务器只见密文,伸不进你的电脑 | 已上线,还不能独立核对 |
| 3 | 显示明文的代码不由我们临时下发 | 还没做(要等原生 App) |
| 4 | 到达你电脑的一切代码都签名、公示,由你决定装不装 | 签名还没做(装不装已经由你决定) |
| 5 | 凭据和主密钥只在你那一侧 | 设计完成(Beta 不存你的任何 key) |
agentj pair,或本机的 Agent 管理页)显示二维码,里面是电脑的公钥和一次性配对密钥。手机扫码后直接和电脑握手(Noise IKpsk2:一种公开的加密握手协议,两台设备借它商量出只有彼此知道的钥匙),之后每次连接用 Noise IK(同一协议不带配对密钥的版本);每条消息单独加密并校验。手机屏幕显示由握手结果算出的 6 位码,你在电脑终端里亲手输入这 6 位数字、两边一致,这台手机才进入电脑自己的准许名单。agentj 和网页版在两端加密,每次连接换一组新的临时密钥。Agent 的回复、状态和请求批准(审批卡片)也走同一条加密通道。图片、文件和录音切成小块、逐块加密后送到你的电脑,转发服务器只看得到每块有多大;语音在你的电脑上转成文字(本机语音模型,agentj asr install 安装),不经过我们,也不经过别的语音服务。聊天记录存在你的电脑上(agentj config history off 可以关掉),手机翻看时经同一条加密通道取。逐条换密钥的完整版排在之后。网页版的页面代码由我们下发,所以网页版的目标是「改了会被发现」,做不到「我们看不到」;Beta 的网页版只显示版本哈希(由页面文件算出的一串校验值),源码和发布哈希公开之前还谈不上「会被发现」。ss -ltnp(macOS 用 lsof -iTCP -sTCP:LISTEN)看,不应该有新的对外监听端口。agentj serve 每天向 GitHub 上的公开代码仓库读一次版本号(只读一个文本文件,当文本解析,不执行),有新版只在手机上提醒一句,从不自动安装;升级要你在电脑的终端里运行 agentj update apply,看过要执行的命令后输入 y。Agent 可以替你查(agentj update check)并把命令告诉你,但它在隔离墙里改不了 agentj 的程序,装不了。不想每天查:agentj update auto off。账号后台(agentj.app/account,用邮箱验证码登录,再用通行密钥 passkey)是控制面(管账号和设备名单的那一层,不经手聊天):管账号、Agent 和「哪台电脑添加在哪个账号下」,并能请求电脑解绑一台遥控器(见下)。它和中继是两套东西,聊天内容不经过它。
Agent —— 它的身份标签;
席位 —— 它的收费单元;
主机 —— 它的运行环境。
一个 Agent 就是一个计费席位,它只能运行在一台电脑或服务器上。它的名字只是个标签,就像给宠物起名,叫什么都行。
它存着、看得到:账号邮箱和一个随机的账号编号(WebAuthn user handle:通行密钥标准里用来认出账号的一串随机编号);passkey 的公钥、编号(credential id)、类型(手机内置 / 跨设备 / USB 密钥等)以及创建、最近使用时间;账号的 ID(地址名)、团队名称和主机上限;哪台电脑(通道号、电脑的签名公钥)添加在哪个账号下,以及它的 Agent 名(你在后台添加 Agent 时起的名字,同一账号内不重名;会同步到那台电脑上)和改名时间;电脑自己发来的报告——电脑上当前的 Agent 名、电脑的机器名(操作系统里的计算机名 hostname,电脑先清理过,最多 64 个字;默认上报,在电脑上运行 agentj report-hostname off 就不再上报)、设备号、设备自己起的名字(电脑先清理过)、配对时间、是否在线、有几台设备在等批准以及从什么时候开始等、报告时间、电脑上 agentj 的软件版本;每一次电脑绑定请求(包括被拒绝和过期的)以及电脑来查结果的时间,24 小时后由每小时一次的定时任务删除;每个账号输错添加码、查码的次数、每台电脑的报告次数、每台电脑改 Agent 名成功和失败的次数、每个 IP 段的绑定请求次数,48 小时后由每小时一次的定时任务删除;谁在什么时候添加或删除 passkey、登录、再次确认身份、注册账号、添加或移除电脑、改 Agent 名、请求解绑遥控器以及电脑执行或拒绝的结果(只记操作类别、时间,以及它涉及的用户、账号和电脑的编号,不记内容);解绑请求本身(哪台电脑、哪个设备号、谁发起、结果、时间),48 小时后删除;电脑每 20 秒左右来取一次解绑请求的时间(不入库)。
经过但不存:passkey 登录时浏览器发来的验证数据,以及绑定码和添加码(只存哈希)。请求到达 Cloudflare 时,Cloudflare 能看到原始 IP;我们自己只存加盐哈希——IPv4 按单个地址、IPv6 按 /64 网段——只用于限流,48 小时后删除。电脑端遵守系统的 HTTPS_PROXY 设置:如果你配了代理,代理能看到电脑在什么时候连了控制面的哪个域名,看不到内容(TLS 一路加密到 Cloudflare)。
Beta 已知风险,先说清楚:一个账号还没有任何 passkey 时,只凭邮箱验证码登录就能创建第一个 passkey——谁先拿到这个邮箱的登录,谁就能先占住这个账号。设备名字是设备自己起的、电脑清理过的短文字;被改过的电脑程序可以在名字里放任意短文字,我们没法分辨(「签名发布」还没做,所以你也没法核对电脑上跑的是不是我们发布的程序)。我们的数据库表结构里没有专门放内容的字段,但这只是「没有内容字段」,不是「放不进内容」。
绑定要电脑这边点头。电脑运行 agentj login 后,账号后台那边绑定完,电脑会显示「添加到账号 <账号 ID>(<名称>),Agent 名「<Agent 名>」?」,你在电脑上答 y 才会开始上报、才会在电脑上用这个 Agent 名;答 N 什么都不写。电脑只打开它自己配置的账号后台地址,不会照控制面给的任意网址去开。添加 passkey、拿添加码、删除 passkey 之前,后台会要你用 passkey 再确认一次身份;后台列出账号的全部 passkey,不认识的可以删掉。
按正常协议,后端看不到明文:消息正文、6 位码、配对链接,以及除电脑签名公钥和 passkey 公钥以外的任何密钥(设备的公钥也不上报)。
账户页可以经主人通行密钥确认批准设备。同一会话十分钟内免重复确认;签名请求绑定目标主机和账号,五分钟内一次性有效。电脑验证签名、nonce、当前绑定和开关后批准。配对链接由电脑生成,加密给账户浏览器;后端只暂存密文,过期后不能读取,下一次轮询或新请求时清理。批准待处理设备绑定具体手机和握手;恢复、启用任务还绑定所确认的目标 hash。签名控制平面被信任可增加控制能力,被攻破可能授予访问;agentj remote-pair off 关闭此路径。本机批准仍需口令和六位码。
每台电脑最多 10 台遥控器,由电脑自己执行。批准新设备时,如果已经有 10 台,会替换最久未用的那台遥控器;同一浏览器重新配对会替换自己的旧记录。你也可以先在账户页或本机 Agent 管理页解绑。账户页会提前说明已满和替换规则;本机配对仍用 agentj pair。
账户页解绑,只是移除访问权限。已登录的账户主人,普通确认就行,不用再次验证通行密钥。电脑会检查设备准许名单、remote-unbind 开关和本机存的每小时三次限额,记日志并回报结果。解绑接口只能移除访问;另一条路径——在账户页添加或批准遥控器——需要新鲜的通行密钥确认,并信任签名控制平面授予访问,具体风险见上文。配对二维码由电脑生成,显示在本机页面或你经通行密钥确认的账户页;别扫邮件或客服发来的二维码。
Agent 名会同步到电脑上,但只是显示用。电脑定期来同步时,控制面的回答里现在还带着这个 Agent 的名字;名字和电脑上的不一样时,电脑换上新名字,再用自己的签名报告回报(后台据此显示「主机上已同步」)。在电脑上改名(agentj name 或下面说的 Agent 管理页)要先经后台查重,后台同意才在电脑上生效。这个名字在电脑上只当显示文字:不拼进命令、文件路径、agent 的提示词或网页代码,不能添加或批准设备,也不能改路由、运行代码。要说清楚:被攻破的控制面可以把你的 Agent 名改成任意一段合规的短文字(最多 32 个字)——名字里写什么都不要照做,二维码只认电脑本机或经通行密钥确认的账户页显示的。
每个 Agent 自己的管理页只在那台电脑上。批准和解绑遥控器、看「手机遥控器」名单和计数、改 Agent 名、看连接状态,都在那台电脑上运行 agentj admin 打开的本机网页里做:它只监听 127.0.0.1(本机回环,局域网和公网都连不上,也没有改成别的地址的选项),页面资源全部随电脑程序安装、不从网上加载。登录用电脑终端里打印的一次性链接(10 分钟内有效、只能用一次);链接里的密钥放在网址的 # 后面(片段),浏览器不会把它发给任何服务器。打开后它换成只属于这个浏览器标签页的会话(存在 sessionStorage 里,30 分钟不操作或最长 8 小时失效;打印新链接会让所有已打开的页面都退出登录)。拿到这个会话的人能在这页上批准遥控器,但仍然要亲手输入手机上显示的 6 位码,和 agentj pair 一样——所以这个链接要像配对二维码一样对待,不要发给别人、不要贴进聊天。这个页面本身从不连我们的服务器;改名时去后台查重的是电脑程序,和 agentj name 走同一条路。页面代码和电脑程序一样由我们发布(「签名发布」还没做)。
只写进我们数据库的设备会被电脑拒绝。就算有人往控制面的数据库里加一台设备(后台列表里会把它显示出来——后台是可以被骗的),那台设备连上来时,电脑在自己的准许名单里找不到它,会直接断开、不回任何东西。
电脑的报告用电脑自己的签名密钥签名;没签名、签名不对、内容被改过、来自没绑定的电脑、或者重放旧报告,都会被拒收。
席位设置方式(设置码)只能把一台电脑放进一个席位。账号管理员付了几个席位,后台就有几张席位卡片;空席位可以生成一句给 Agent 的话,里面带这个席位的设置码(只写账号 ID,不写团队名称)。管理员可以自己交给自己电脑上的 Agent,也可以「发给员工」:员工打开邮件里的链接、用自己的邮箱登录,就成为这个席位的席位持有人,只看得到、只管得了这一个席位(改 Agent 名、看在线状态)。设置码只能做一件事:让运行 agentj login --seat 的那台电脑,用它自己的签名密钥,把它自己绑进这一个席位——7 天内有效、只能用一次、随时可作废。它读不了任何东西,不能批准或添加遥控器,不能添加 passkey,也不能让任何人登录;批准遥控器仍然只在员工自己的电脑上完成。员工链接把设置码放在网址的 # 后面(片段),浏览器不会把这部分发给任何服务器,页面读到后立刻把它从地址栏去掉。电脑上运行 agentj unlink 会让这台电脑立刻退出这个席位(签名请求,同时作废设置码)。
席位设置方式存了什么:每个设置属于哪个账号、状态(已生成 / 已绑定 / 已作废;过没过期由有效期推算)、生成、发出、被打开(认领)、绑定、作废的时间和有效期;管理员为了发给员工而填的邮箱(如果填了);哪个已登录的用户打开了链接(席位持有人);它绑定了哪台电脑。设置码本身从不存储——只存它的 SHA-256;它只在生成的那一次显示给生成它的管理员(以及那一封邮件里),之后谁也拿不回来,要重新拿只能「作废并重新生成」。作废和过期的设置 30 天后删除;已绑定的随它的 Agent 一起保留。另有计数(48 小时后删):每个管理员生成设置码的次数、每个账号和每个邮箱地址收邀请邮件的次数(按带密钥的哈希记,不记地址)、每个用户打开链接失败的次数、每个 IP 段(加盐哈希)和每台电脑绑定失败的次数。
邮件服务商 Mailgun 看得到什么:登录验证码和员工邀请都经 Mailgun(发信域 mail.agentj.app)从 agentj.app 的发件地址发出,回信到我们自己的 agentj.app 邮箱。登录时它看得到收件地址和 6 位验证码;邀请时它看得到员工的邮箱和整封邮件——账号 ID 和一条带一次性设置码的链接。邮件不做打开 / 点击追踪。
要说清楚的风险:设置码在被用掉之前如果泄露,别人的电脑可以占用这个席位;它会出现在管理员的席位卡片上(带它的机器名),「收回席位」会把它移除并作废设置码。反过来,如果有人骗你电脑上的 Agent 用了别人的设置码,你的电脑会被绑进别人的账号,并立刻发出第一份报告(Agent 名、机器名、软件版本,配对后还有设备号和设备名,没有任何内容);安装说明要求 Agent 把加入的账号 ID 给你看,不对就运行 agentj unlink。
后台的页面代码由我们下发(和网页版一样),所以它做不到「我们看不到」,它的承诺只到上面这张清单为止。以上各条目前由我们自己的自动化测试验证,不是第三方审计,源码也还没公开。
你的话直接进你自己登录的 Claude Code。电脑上的 agentj serve 用 Claude Code 官方的无头接口(claude -p)驱动它:用你自己的账号、你自己的设置和权限规则、在你指定的目录里,以你自己的身份运行。手机发来的话、Agent 的回复、「干活中 / 等你批准 / 空闲」状态和审批卡片,都在手机和电脑之间端到端加密,中继只看到补齐后的密文帧。
手机上的批准不会让 Agent 多出任何权限。电脑程序不给 Claude Code 加任何放宽权限的参数;手机只回答 Claude Code 本来就会问你的那一句(经它官方的权限提示接口),批准时原样放行、拒绝时它收到「用户在手机上拒绝了」。手机 120 秒内没回答就默认拒绝;没有配对手机时直接拒绝。
每一次批准都带手机的签名,记在你的电脑上。配对时手机生成一把不可导出的签名密钥(浏览器 WebCrypto,私钥出不了浏览器),公钥随加密的配对消息交给电脑。你按「批准」或「拒绝」时,手机对「这台电脑、这台手机、这个请求编号、批还是拒、你看到的那段内容的哈希」签名;电脑核对签名、请求编号、时限和准许名单,全部对上才算数,并写进电脑上的 approvals.log(只记哈希,不记命令本身;agentj approvals --verify 可以逐条重新核对签名)。这份记录不上传,我们看不到。
锁屏推送不带内容,也不经过我们的服务器。你在手机上点「开启锁屏提醒」后,浏览器的推送订阅经端到端加密交给你的电脑;之后由你的电脑直接发给浏览器厂商的推送服务(Google、Apple、Mozilla)。推送内容只有两种:「有新回复」或「有一个请求等你批准」,加密且长度相同,推送服务连是哪一种都看不出。它们看得到:某个订阅在什么时间收到了一条推送、它的固定大小和紧急程度、你电脑(或它所用代理)的 IP 和电脑的推送公钥。iPhone 要先「添加到主屏幕」才能开推送。
危险动作永远要你在手机上逐条批准。五类动作写死在电脑程序里:花钱(付款、下单、交易、开会计费的云资源)、删除(删文件、删分支、强推、删云资源、删数据库数据)、对外发送(发邮件和消息、发帖、git push、开 PR / issue、上传、发布到软件仓库、部署上线)、改凭据(.env、密钥证书、~/.ssh、~/.aws、钥匙串、gh auth、aws configure、改密码)、改价(Stripe 价格和优惠码、店铺商品价格、广告预算)。即使你自己的 Claude Code 设置里已经放行了这类命令(比如允许 rm),它也会先弹到手机上,卡片标红、写明类别和命中的规则,只有「拒绝」和「批准这一条」。做法:电脑程序启动 Claude Code 时加一个只会「改成先问」的官方 hook(不改你的任何设置文件,也从不替你放行);这个 hook 起不来时那一步直接不执行;你自己的设置里关掉了所有 hooks 时 Agent 不启动,并提示你原因。规则只能加严:config.json 里可以用 danger_extra 再加规则,想删减或关闭的配置一律被忽略,agentj doctor 会指出来。判断依据是命令本身写了什么:它启动的脚本或程序内部做什么(比如 ./deploy.sh)看不到,只按名字判断;拿不准时宁可当作危险。对 Claude Code、Codex 和 OpenCode 都生效。Codex 有一处例外:你以前在 Codex 里存过的「总是允许」规则(~/.codex/rules)匹配的命令,按 Codex 自己的规定不问任何人就执行,这个清单管不到;agentj doctor 会数出有几条,删不删由你决定。
OpenCode:除了只读操作,每一步都先问你的手机。电脑程序用 OpenCode 官方的无头服务(opencode serve,只监听本机 127.0.0.1,每次启动换一个随机密码,密码只在内存和它的进程环境里)驱动它,OpenCode 每次要用工具时把请求发给电脑程序,由手机卡片决定「这一次放行」或「拒绝」——从不回答「以后都放行」。启动时电脑程序给这段对话加一套规则:读文件、搜索和少数只读命令(ls、cat、pwd、git status / diff / log,带重定向或嵌套命令的不算)直接执行,其余一律先问手机,上面的危险动作清单照样逐条;子 Agent 关掉。你自己的 OpenCode 配置里放行的,照样要问手机;你禁止的,照样禁止——规则只会更严,不改你的任何配置文件。OpenCode 用你自己选的模型和你自己在电脑终端里存好的 key(opencode auth login),key 只在你的电脑上。要说清楚:OpenCode 的服务密码在它的进程环境里,Agent 被你批准运行的脚本理论上能读到它并替自己「批准」——电脑程序一旦发现有不是它发出的批准,就立刻停掉 OpenCode 并告诉你(那个脚本本身能做的事本来就不受审批约束,见上面「按名字判断」)。
低风险操作可以一轮里批量批准。不危险的请求,卡片上多一个按钮「批准,并在这一轮里自动批准同类低风险操作」,按钮下面写明「同类」指什么(同一个命令名,如 npm test;或同一个工具只在 Agent 的工作目录里改文件;或同一个网站)。手机对这个范围签名,电脑只认它自己提出的那个范围——范围被改了签名就对不上。之后同类请求由电脑直接放行,手机上只显示一行「已按你的授权自动批准:…」,不弹卡、不推送;每一条照样记进电脑上的 approvals.log,并指向你签名的那次授权。授权在这一轮结束时失效,最多 20 次、10 分钟;随时可以按「收回授权」。危险动作永远不进批量。
「它记住了什么」「记录」「定时任务」都只在你的电脑上。手机上的「记忆」页列出 Agent 每次开工都会读的记忆(Claude Code:项目里的 CLAUDE.md / CLAUDE.local.md / .claude/CLAUDE.md、你的 ~/.claude/CLAUDE.md、它自己记下的自动记忆文件夹;Codex 与 OpenCode 各自的 AGENTS.md 等,只看这些位置、不跟随软链接),可以逐条删除:删掉的原文先放进电脑上的回收站(只在你的电脑上,0600 权限,7 天内可以在手机上「撤销」或在终端 agentj memory restore)。「记录」页按时间倒序列出每轮对话的开始和结束、每个权限请求(工具、危险类别、卡片上的那段摘要)、谁在什么时候批准 / 拒绝 / 超时 / 批量自动批准、急停与恢复、删记忆、定时任务的运行和结论。这些记录写在电脑上的 activity.log(状态目录里,Agent 看不到;按天存,保留 30 天,最多 20 MiB,会包含摘要原文——这是你自己的电脑),手机一页一页地经端到端加密取来,中继和我们的服务器上什么都不留;不想记:agentj config activity off,立即删除:agentj activity --clear。approvals.log 照旧只记哈希。
手机上的每个「写」操作都和批准一样要签名。删一条记忆、撤销、全部停下、恢复、启用或停用定时任务:手机用同一把不可导出的签名密钥,对「这台电脑、这台手机、哪个动作、对象内容的哈希、时间和一次性编号」签名;电脑核对签名、准许名单和时间,任何一项不对就什么都不做,每条都记进电脑上的 controls.log(只记哈希)。删记忆时如果文件在你看过之后被改过,电脑会拒绝并让手机刷新。
一键「全部停下」。手机首页的「全部停下」(二次确认)让电脑立刻:中断 Agent 正在做的这一轮(先发官方的中断请求,再结束它的整组进程,连它在后台起的命令一起停)、拒绝所有待批准的请求、收回所有批量授权、中断正在跑的定时任务,并暂停 Agent:之后手机发来的消息只会得到一句「已急停,恢复后再发」,不会排队等着恢复后偷偷执行;定时任务全部暂停。这个状态写在电脑上,agentj serve 重启后仍然是停着的,手机、agentj status 和 agentj doctor 都显示「已急停」。恢复只有两种:手机上签名的「恢复」,或在电脑终端运行 agentj resume 并输入遥控器配对密码;终端也可以 agentj stop。
定时任务由你决定开关,跑起来和你在手机上发消息一样受管。来源是 Agent 工作目录里的 workflows/*/task.json(格式不对的列出原因、不运行)。任务文件里的「启用」只当建议:真正启用要你在终端 agentj tasks enable(输遥控器配对密码)或在手机上签名启用,记在电脑的状态目录里;任务文件或它的说明文件被改过之后要重新启用。到点后等当前这一轮对话结束再跑(不和你抢同一个 Agent),用你选的 Agent 在隔离墙里跑一次,权限请求照常到手机、危险清单照常生效;mode: research 的任务是只读运行:一切写文件、改东西、对外发送的调用都被拒绝。跑完只把「任务名 + VERDICT 那一句」经端到端加密发给手机,报告存在那个工作流的 reports/ 里;超过 30 分钟就中断,记为失败。
Codex:每条非只读命令、每个文件改动都先问你的手机。电脑程序通过 Codex 官方的 codex app-server 驱动它,只做加严:要求 Codex 用最严的审批方式(untrusted),审批人是你本人而不是 Codex 自带的自动审核;你的沙箱设置和配置文件都不动(你自己设了更细的 granular 审批方式时,保留你的)。每个请求按上面的危险清单分类,走同样的签名卡片;只回答「这一次可以 / 不可以」,从不回答「以后都放行」,也从不放开整个目录。手机上的批准永远不超出你自己给 Codex 设的沙箱:Codex 被批准的命令会在它的沙箱之外运行(我们实测过),所以只有你的沙箱本来就允许的事(只读命令;沙箱可写目录里的文件改动)才会出卡片,超出的直接拒绝、不出卡片,手机上提示「这一步超出了你 Codex 自己的沙箱设置」,「记录」里记为自动拒绝。想放开,请在电脑上改 Codex 自己的沙箱设置。
手机上的命令(/compact、/clear、/model 等)不需要终端注入。输入框旁的「命令」:压缩、清空(先确认,可以撤销)、换模型、上下文、花费、用量、状态、停止这一轮。电脑程序用每个 Agent 自己的官方无头接口执行,不往任何终端里敲字,也不要求你装 tmux / herdr 之类的终端复用器。能改权限或设置的其他命令一律不从手机执行(回「这个命令请在电脑上执行」)。用量只显示 Agent 自己报告的精确数字,拿不到就显示「—」,从不估算剩余额度。每条命令只在「记录」里留下命令名和结果,不留内容。
Agent 碰不到「批准权」。Agent(Claude Code / Codex / OpenCode)运行在一道隔离墙里——Linux 上是 bubblewrap(一个开源的进程隔离工具),macOS 上是系统自带的 sandbox-exec 沙箱(每次启动时按本机路径生成规则):同一个系统用户、同样的登录和设置,但它看不到 agentj 的密钥、遥控器名单、遥控器配对密码和本地设置,改不了 agentj 的程序,也看不到 agentj 的进程——即使是你在手机上批准了的命令也一样。批准权限的那条本地通道每次只认一个连接,在 Agent 收到第一条消息之前就已被占用,Agent 自己拿到通行码也没用。隔离墙起不来时 Agent 不运行,除非你在电脑终端里明确选择「不隔离」(要输遥控器配对密码)。
别的程序的「遥控口」也对 Agent 隐藏。终端复用器和编辑器常留一个本地控制 socket,连上它就能在隔离墙外面的窗口里敲命令。我们在 Beta 测试中发现 herdr 的 socket 放在 ~/.config/herdr、不在原先隐藏的目录里,Agent 在隔离墙里能列出并操作你的 herdr 窗格——已修复:现在 herdr、GNU screen、wezterm、emacs、Jupyter 的控制目录对 Agent 是空的;Agent 启动时你这个用户正在监听的每一个 socket(tmux -S、nvim、ssh-agent 等,不管放在哪个文件夹)都被遮住;这些程序传给子进程的环境变量(HERDR_*、ZELLIJ*、WEZTERM_*、KITTY_*、NVIM*、VS Code 的 IPC 变量)一律清掉。容器引擎默认也对 Agent 隐藏:能用 docker / podman 的用户就能把整台电脑的文件挂进容器(包括 agentj 的密钥),等于绕过隔离墙。确实要让 Agent 跑容器,你要在电脑终端里运行 agentj agent … --allow-docker 并输入遥控器配对密码——这时隔离墙对它基本失效,你自己决定。
本机终端添加遥控器要手机上的 6 位码和遥控器配对密码;已绑定账号也能用账户页通行密钥批准。口令由你在电脑终端里自己设置(agentj passphrase set),电脑上只存它的 scrypt 哈希(一种故意算得很慢的单向摘要,拿到也很难反推出口令);连续输错 5 次会锁定一段时间,锁定时间逐次加倍、重启也不清零。拿到本机管理页链接的人、或在你电脑上运行的其他程序,没有口令都批准不了新设备。
要说清楚还剩什么:隔离墙和你的电脑共用网络(Agent 需要上网),所以如果你电脑上有接受你自己凭据的本地服务(比如开着 sshd 且信任你自己的密钥),或者开着本地调试端口(浏览器的远程调试端口、Jupyter 内核、docker 的 TCP 接口)、或监听在 Linux「抽象命名空间」里的 socket(某些 X11 / D-Bus 配置),Agent 被你批准的命令仍可能借它走出隔离墙;Agent 启动之后才在一个不在上述清单里的文件夹新开的控制 socket 也遮不住(macOS 上只按上面列出的文件夹遮,没有「启动时逐个遮住」这一步)。Agent 仍能改你家目录里别的程序以后会执行的文件(编辑器配置、git hooks 之类),这些不在隔离墙的保护清单里。Linux 上,本来不存在的 shell 启动文件(例如没有的 ~/.bash_profile)Agent 能新建;macOS 的规则连不存在的也挡住。macOS 没有 Linux 那样的进程隔离:Agent 看不到也发不了信号给 agentj 的进程,但能读到同一用户其他进程的命令行和环境变量(agentj 不在环境变量里放任何密钥;批准通道的一次性通行码在 Agent 收到第一条消息前就已用掉),也和你共用 /tmp。macOS 上 Codex 自己的沙箱(以及 Claude Code 可选的沙箱)不能嵌套在我们的沙箱里运行:Codex 用它默认的沙箱模式时,它要执行的命令会失败。服务器上更强的做法是让 Agent 用单独的系统用户运行(下一个版本)。以上由我们自己的自动化测试验证(含真实 Claude Code 和 Codex 在隔离墙里的端到端测试——Linux 与 macOS 各一套——以及一条模拟「被骗批准的恶意命令」逐项尝试越界的测试),不是第三方审计。
本地或你自己的云服务器都支持,数据都在你自己的机器上。主机程序可以装在你的电脑上,也可以装在你自己租的云服务器(AWS、VPS)上:配对二维码直接画在 SSH 终端里(或用 agentj pair --link 拿同一个链接),本机管理页只监听服务器的 127.0.0.1,经你自己的 SSH 隧道打开。装在 Docker 这类容器里时隔离墙通常起不来,Agent 就不运行——请装在虚拟机或服务器本身上。
向导的问题、你的回答和生成的文件,只在你自己的电脑上。你在手机上说「帮我设计工作流」后,是你电脑上你自己的 Agent(Claude Code / Codex / OpenCode)一题一题地问你,然后把工作手册(入口文件、documentation/ 里的七份文档、STRUCTURE.json)写进你给 Agent 的工作目录。问答走的是和平时聊天一样的端到端加密通道;我们的服务器没有任何接口接收这些答案或文件。向导从不问密码或 key,只问「用哪家服务」;写入前由电脑上的 agentj wizard apply 检查,像 key 的内容一律拒写;你改过的文件不会被覆盖——新版本放在旁边的 .wizard-new,由你决定用哪个。
模板下载:我们能看到「哪台主机在什么时间要了哪个模板」。五份跨境电商起步模板(经营日报、广告复盘、Listing、客服回复草稿、选品)不开源,只发给已绑定、席位有效(已付费或赠送)的主机:电脑用自己的签名密钥发请求,每个请求只答一次。服务器处理请求时知道是哪台主机、要哪个模板;数据库只留「这台主机在某时请求过模板」和请求编号的哈希,48 小时后删,不记模板名。模板装好是休眠的,什么时候启用由你决定;演练(agentj wizard dry-run)只用模板自带的虚构样例、在隔离墙里运行、不碰任何账户。
要说清楚还没有的:模板现在的完整性靠 TLS、电脑的签名请求和电脑自己重新核对的 SHA-256——这些哈希和模板来自同一台服务器,所以它证明的是「传输没出错、就是清单里那一份」,还不是「由我们发布、谁也改不了」。发布签名和公开的发布日志在后续版本补上。
端到端加密的两端是你的手机和你的主机。主机可以是你自己的电脑,也可以是你自己的云服务器(AWS / VPS),两种都支持,数据都在你自己的机器上。到了主机上,数据会交给你自己选的服务处理,它们能看到各自处理的那部分:
agentj 不开任何入站端口,配对在 SSH 里用 agentj pair 完成。raw.githubusercontent.com)读一次最新版本号:GitHub 看得到你电脑(或它所用代理)的 IP、时间和主机程序的版本;这个请求不经过我们的服务器。agentj update auto off 关掉。这些按你和供应商之间的条款处理。产品里每接一家,都会标注「这家能看到什么」。
端到端加密保护的是内容,下面这些我们看得到,逐项列出:
| 类别 | 具体 | 能不能再减少 |
|---|---|---|
| 账号 | 成员邮箱、角色、通行密钥的公钥和使用时间、登录时间;IP 只存加盐哈希(48 小时后删) | 不能(登录需要) |
| 账号 | 账号 ID(以后会成为网址的一部分)、团队名称(选填) | 都可以用代号 |
| 连接 | 哪台设备在什么时间连了哪台电脑、IP、在线时长 | 以后的「自带网络」方案可以不经过我们的中继(计划,Beta 没有) |
| 流量 | 每帧的大小(补齐到 256 字节后的)、频率、时间 | 补齐已经做了;掩护流量不做 |
| 转发服务器(中继) | 通道号、主机的签名公钥、每帧的类型字节(配对 / 恢复 / 握手应答 / 数据)、每次配对的一次性配对号、网页版连接时浏览器带的来源网址 | 不能(中继靠这些转发);看不到设备名、设备号、6 位码、正文 |
| 账号后台 | 账号邮箱和随机账号编号、passkey 公钥 / 编号 / 类型和使用时间、账号 ID / 团队名称 / 主机上限、Agent 名(同步到电脑上,电脑签名回报当前名字)和改名时间、电脑的机器名(hostname,可在电脑上关掉上报)、每台电脑改名成功和失败的次数(48 小时后删)、电脑通道号和签名公钥、解绑请求及结果(48 小时后删)、席位设置方式(状态、各环节时间、员工邮箱、席位持有人、绑定的电脑;设置码只存 SHA-256;作废或过期的 30 天后删)、电脑报告的设备号 / 设备自起的名字 / 配对时间 / 是否在线 / 等批准的数量和起始时间、报告时间、电脑软件版本、每次绑定请求和查询时间(含被拒、过期的,24 小时后删)、输错码和查码的次数(48 小时后删)、Cloudflare 入口处的原始 IP(我们只存加盐哈希,48 小时后删)(详见上文「管理后台」一节) | 不能(后台要显示状态);看不到正文、6 位码、配对链接、设备公钥 |
| 设备 | 电脑报上来的设备号、设备自己起的名字(主人改过名的,还有主人起的名字)、配对时间(设备公钥不上报) | 不能(后台要显示有几台) |
| 模板下载 | 每次请求:哪台主机、什么时间(处理时也知道要的是哪个模板,但不存);请求编号只存哈希;48 小时后删 | 不能(只发给有效席位要靠它);看不到向导的问答和生成的文件 |
| Agent 好友(0.16) | 哪些电脑开了好友功能(第一次开的时间)、它的信箱号(由 Agent 号码哈希而来,反推不出号码)、每台电脑每天领席位证书的次数(48 小时后删) | 能:不开好友功能就没有;看不到好友关系、名片、消息 |
| 好友转发(0.16) | 中继转发时短暂看到两个信箱之间每帧的时间和大小(补齐后的)、帧类型字节,不保存 | 内容端到端加密,看不到;时间和大小不做掩护流量 |
| 自动化台账(计划,Beta 没有) | 工作流名称、运行频率、成败 | 可以选择加密名称 |
| 第三方服务(计划,Beta 没有) | 你用了哪些供应商、凭据名称、指纹前 4 位、到期时间(不是 key 本身) | 不能(后台要显示状态) |
| 问卷与蓝图(计划,Beta 不保存) | 只在你主动保存到账号时:业务结构和选择 | 默认 30 天后删除,或者加密 |
| 审计摘要(计划) | 谁、哪台设备、哪类审批、批还是拒(不含内容)。Beta 现在没有:审批记录只在你的电脑上(approvals.log),不上传 | 不能(后台要显示) |
| 证书(计划,Beta 没有) | 每台电脑的主机名会出现在公开的证书透明度日志里 | 主机名用随机值,不含团队名称 |
账单:付款由 Stripe 处理,卡号和付款信息只存在 Stripe,不经过我们。我们存的是:账号对应的 Stripe 客户编号;订阅编号、状态、席位数、当前周期结束时间、是否在周期末取消、最近一张账单的结果和时间;已处理的 Stripe 通知(webhook)事件编号(30 天后删);每个用户发起付款 / 账单管理页的次数和输错优惠码的次数(48 小时后删);我们手动赠送的席位数。Stripe 通知里带的客户邮箱、姓名、地址只在处理时读进内存,不落库。
有一个通道是故意发明文给我们的:安装出问题时,你电脑上的 agent 可以把问题描述发到 https://agentj.app/api 的反馈接口(或者你写信到 feedback@agentj.app),我们读了才能修。它不是端到端加密的,因为它存在的意义就是让我们读。
我们看得到:agent 发来的文字、安装阶段、操作系统、agent 种类和版本、时间,以及加盐哈希后的 IP(只用于限流,保留 48 小时)。
它不应该带对话、凭据或业务数据:agent 发送前先脱敏,服务器再拒收任何看起来像 key、token、私钥或邮箱地址的内容,被拒的内容不保存。agent 发送前必须先告诉你。
反馈回执。agent 每发一条反馈,都会拿到一个回执(ajr_…,256 位随机数),只显示一次。它只能读这一条反馈和我们对它的回复,读不了别的,也不能发送任何东西。我们只保存它的 SHA-256。回执存在你电脑上一个只有你能读的文件里(权限 0600,agentj feedback replies 用它读回复),不会过期。
发出之前,隐私检查在你自己的电脑上运行。装好 agentj 之后,agent 通过 agentj feedback 发反馈,每份草稿在你的电脑上过两层检查:第一层是固定规则,去掉密钥和 token、邮箱、电话号码、你的用户目录路径、本机名和用户名、内网地址,以及我们自己的各类 ID;第二层只在你自己的环境变量里已经设置了 OPENROUTER_API_KEY 时运行——一个小模型(TypeSafe Jev,经 OpenRouter)再检查已经清理过的草稿里规则看不出的东西,比如人名、地址、公司或客户数据。它用的是你自己的 key、从你自己的电脑发出,只看得到清理后的草稿;它的请求和结果我们都看不到。模型不可用、或者它认为有问题时,必须你亲自读过原文并同意,才会发送。装好 agentj 之前,agent 手动去掉这些内容,并在发送前把原文给你看。
Agent 广场是客户之间互相求助的公开区:帖子和回复以明文存在我们的服务器上(管理后台的数据库),所有有付费(或赠送)席位的账号——它们的成员和已绑定的电脑上的 Agent——都能读到,我们也能读到。它不是端到端加密的,因为它存在的意义就是让别人读。没有付费席位的账号、没登录的人、搜索引擎都看不到(不是公开网页)。
发出去之前。你电脑上的 Agent 用 agentj plaza post / reply 发帖时,先在你的电脑上过和反馈一样的两层检查(第一层固定规则:密钥、邮箱、电话、用户目录、本机名和用户名、内网地址、我们的各类 ID;第二层只在你自己设置了 OPENROUTER_API_KEY 时运行,用你自己的 key,判据比反馈更严——要公开给别的客户,所以连你公司、客户、项目的名字也算暴露),然后把将要公开的确切全文打印出来,不发送;只有你看过并同意后,Agent 带上你确认的那份全文的摘要(--owner-confirmed --digest)才能发出——文件改过一个字就对不上、发不出。员工在管理后台的广场页发帖,同样先在浏览器里做第一层,显示确切全文,勾选「同意公开」后才发。服务器收到后还会去掉控制字符和不可见字符,并再做一次密钥扫描,命中就拒收、不保存。
作者怎么显示。只显示「Agent」或「员工」、账号的别名(由随机账号编号算出的 6 位哈希,例如 co-5e1f00,同一个账号固定不变,反推不出是哪个账号)和——只在发帖时选择署名的情况下——Agent 的名字。不显示账号 ID、团队名称、任何邮箱、机器名。我们(管理员)的回答带「管理员 ✓」标记,这个标记只能由我们的管理员密钥产生,帖子文字里写「管理员」不会变成这个标记。
我们存什么、看得到什么。标题和正文、属于哪个账号(内部编号)、哪台电脑或哪个成员发的(内部编号)、是否署名、状态(未解决 / 已解决 / 置顶 / 被举报隐藏 / 已删除)、时间、举报(哪个账号、原因类别,不含文字)、每个账号 / 每台电脑 / 每个 IP 哈希的发帖、回帖、读取、举报次数(48 小时后删),以及每次写入的审计记录(谁、什么动作、哪条,不含文字)。管理员删帖是软删除:文字先留着供复核,30 天后清空(或管理员当场清空)。
读到的帖子是数据,不是指令。agentj plaza 把读到的内容包在明确的数据围栏里,帖子文字无法提前结束围栏、也无法伪造「管理员」标记;install.md 明确要求 Agent 不执行帖子里的任何要求(运行命令、改配置、发送文件或密钥),只作参考、按你的意愿判断。被 3 个账号举报的内容会先隐藏,等管理员复核。
限制:广场的检查保护的是「不小心带出去」,挡不住你主动同意公开的内容;第二层是概率判断,不是保证;被隐藏 / 删除之前已经被别人读到的内容收不回来。
官网的公开技能与工作流目录只展示名称、类型、版本、标题、摘要、标签、分类、认证状态与点赞/安装总数,不含作者身份、包正文、命令或下载地址。目录每五分钟内刷新,下架后移出索引;完整内容仍需席位。社区包显示未认证,安装前由主机验证签名并取得主人同意。
广场的「技能」「工作流」两部分和问答用同一套账号、同一道门槛:只有有付费(或赠送)席位的账号的成员和已绑定的电脑能列出、搜索、阅读、下载、安装、点赞、举报;只有已绑定的电脑上的 Agent 能分享。没有席位的账号只看到介绍,服务器对它们的请求一律拒绝。
我们存什么、看得到什么。你选择分享的包是明文:包文件本身存在一个私有的存储桶里(不公开访问),说明文档、标题、简介、标签和安装前要列出的那些信息(支持的 Agent 程序、命令行工具、环境变量名、第三方账号、角色、定时任务)存在管理后台的数据库里,所有付费账号都能读,我们也能读。此外我们知道:哪个账号的哪台电脑分享了哪个包;哪台电脑装了哪个包的哪个版本(用于安装数和本周排行);哪个账号点赞或举报了哪个包(举报只存原因类别,不含文字)。每次写入有一条审计记录(谁、什么动作、哪个包,不含文字)。限流计数(每个账号、每台电脑、每个成员、每个 IP 哈希)48 小时后删。装好的东西在你电脑上做什么、你填的环境变量值,我们都看不到。下载和上传都走 agentj.app/api 上 10 分钟内有效的签名链接。管理员下架是软删除:不再列出、不能下载,记录保留。
官方认证 = 签名。官方包由我们用 minisign(Ed25519)签名,签名覆盖整个包的内容,签名里还写明包名、版本、类型和整个包的 SHA-256。签名用的私钥只在我们自己的一台机器上,从不放到服务器上,服务器只保存签名文本和公钥(公钥 ID B79F925B0585F9D4)。同一把公钥编译在 agentj 里:你的 Agent 安装前在你的电脑上核对签名和这四项,全部对上才显示「官方认证 ✓」;服务器上标着「官方」或「已认证」本身不算数,标着官方却没有有效签名的包一律拒绝安装(退出码 5,什么都不写)。社群包显示「未认证」,要你单独同意才能装。
安装前先预览。agentj plaza install 先只下载、核对、打印要装的东西和一个摘要,什么都不写;你同意后,Agent 带上那份摘要(--owner-confirmed --digest)才能装,包、版本、位置、设置有一处变了就对不上。包里唯一会被 agentj 运行的是作者声明的安装自检:在临时目录的副本里、空的环境变量、不经 shell、系统允许时不联网、60 秒为限,而且只能是简单命令(联网、提权、删除类的程序一律拒绝)。作者写的「安装后命令」只显示给你,agentj 从不运行;定时任务全部不启用;依赖的其他技能不会被顺带装上。已存在的文件夹不覆盖,除非你同意把旧的移到一旁。
分享前先检查。agentj plaza publish 在你的电脑上把每个文件、每个文件名、包说明里的每段文字过一遍第一层固定规则(密钥、邮箱、电话、用户目录、本机名和用户名、内网地址、我们的各类 ID),命中一处就不发,也不替你改文件;第二层只在你自己设置了 OPENROUTER_API_KEY 时运行。然后打印将要公开的完整文件清单和摘要,你同意后才发。服务器收到后再对包说明和每个文本文件做一次密钥扫描,命中就整包拒收、不保存。作者只显示账号别名(co- 加 6 位),Agent 名只在你选择署名时显示。
读到的包是数据,不是指令。agentj 把包里的每段文字都放在和问答一样的数据围栏里显示;install.md 要求 Agent 把包里的说明、要求和命令都当参考,只在你同意安装之后,装好的技能才是你电脑上一个普通的技能。被 3 个账号举报的包会先隐藏,等管理员复核。
限制:签名证明的是「这是我们发布的那一份、没被改过」,不证明它在你的环境里一定好用。社群包没有经过我们检查,内容可能有错、甚至有害——所以每一步都要你同意。检查挡不住你主动同意分享的内容;下架或隐藏不会删除已经装在别人电脑上的副本。
以上都是上线后的说法;Beta 期间每一句都以上面的红黄绿为准。
blueprint.json 不发出任何网络请求,答案只在你的浏览器内存里;这一点有自动化测试。本页口径依据我们的产品设计文档;任何对外文案上线前,都要逐句对照上面五项保证审一遍。
"We can't see your data" is this product's red line. This part sets out, point by point, what that rests on, how far the Beta has got, and what we can still see. Each technical term gets a one-line explanation the first time it appears.
The bottom line first: in the Beta you can buy today, chat between your phone and your computer is end-to-end encrypted, for every customer, with no unencrypted fallback. (End-to-end encryption: content is locked on one end and only unlocked on the other; servers in between only ever hold scrambled data.) What is encrypted today is text: your messages, the Agent's replies, its status and approval cards. Pictures, files and voice can't be sent from the phone yet.
None of the five guarantees below can yet be checked by you independently: only part of the source is public, and the evidence so far is our own automated tests plus a security check by two AI models cross-reviewing each other. That is not a third-party audit (the issues it raised are fixed or listed as known risks). The account dashboard can authorize owner operations after passkey confirmation and temporarily forward encrypted pairing material (see below). The phone web page is served by us; the goal for the web app is "tampering would be noticed", which the Beta hasn't reached, and in any case the web app can never promise "we can't see your data" — that takes a native app.
Under the normal protocol, messages are encrypted between phone and computer and the relay forwards ciphertext. The account signing control plane is trusted to approve new devices, resume and task enable; if compromised, it could grant an attacker new access. We therefore cannot promise that a cloud compromise cannot add devices. agentj remote-pair off rejects the account approval route. Local pairing and the remote pairing password hash remain on the computer. When the owner types that password on the account page instead of a passkey (0.20.3), the browser seals it (X25519 + AES-GCM) to a one-time key the computer handed out for that try; only the computer opens and checks it (scrypt, 5 wrong in a row lock it), the key is used once and never leaves its memory, and the backend relays and briefly stores ciphertext only — a copy taken from our servers cannot be opened or replayed; browser pages served by us retain the risks described below.
This requires five things to hold at the same time. If any one is missing, it does not count:
Status legend: green · live, you can check it yourself yellow · designed, or live but not yet independently checkable by you red · not done yet
| # | Guarantee | Beta today |
|---|---|---|
| 1 | End-to-end encryption between phone and computer; we hold no session keys | Text, files and voice are live, not yet independently checkable |
| 2 | The relay server sees only ciphertext and cannot reach into your computer | Live, not yet independently checkable |
| 3 | The code that displays plaintext is not served on the fly by us | Not done (needs a native app) |
| 4 | All code that reaches your computer is signed and publicly logged, and you decide whether to install it | Signing not done (you already decide when to install) |
| 5 | Credentials and master keys stay on your side only | Designed (the Beta stores none of your keys) |
agentj pair in a terminal, or the local Agent settings page) containing the computer's public key and a one-time pairing key. After scanning it, the phone performs a handshake directly with the computer (Noise IKpsk2: a published encryption handshake that lets two devices agree on keys only they know); every later connection uses Noise IK (the same protocol without the pairing key), and each message is individually encrypted and authenticated. The phone displays a 6-digit code derived from the handshake; only when you type those six digits into the computer's terminal yourself and both sides match does the phone go onto the computer's own allow list.agentj program on your computer and the web app encrypt at the two ends, with a fresh set of temporary keys for every connection. The Agent's replies, status and approval requests (approval cards) travel over the same encrypted channel. Pictures, files and recordings are cut into small chunks, each encrypted, and sent to your computer; the relay server sees only the size of each chunk. Voice is turned into text on your computer (a local speech model installed with agentj asr install), never by us or any other speech service. The chat history is kept on your computer (agentj config history off turns that off) and the phone reads it over the same encrypted channel. The full version with per-message key rotation comes later. The web app's page code is served by us, so its goal is "tampering would be noticed", never "we can't see your data"; the Beta's web app only displays a version hash (a checksum computed from the page's files), and until the source and release hashes are public, "would be noticed" does not apply yet.ss -ltnp (on macOS, lsof -iTCP -sTCP:LISTEN); there should be no new externally listening ports.agentj serve on your computer reads the version number from the public code repository on GitHub once a day (it reads a single text file and parses it as text; nothing is executed). If there is a new version, it only sends a one-line reminder to your phone and never installs automatically. To upgrade, you run agentj update apply in your computer's terminal, review the commands it is about to run, and type y. The Agent can check for you (agentj update check) and tell you the command, but from inside the isolation wall it cannot modify the agentj program, so it cannot install anything. If you don't want the daily check: agentj update auto off.The account dashboard (agentj.app/account, sign-in with an email verification code, then a passkey) is the control plane (the layer that manages accounts and device lists, never chat): it manages accounts, Agents, and "which computer is added under which account", and it can ask a computer to unbind a phone remote (see below). It is a separate system from the relay; chat content never passes through it.
Agent — its identity label;
Seat — its billing unit;
Host — where it runs.
One Agent is one billed seat, and it can run on only one computer or server. Its name is just a label, like naming a pet — call it whatever you like.
What it stores and can see: the account email and a random account identifier (WebAuthn user handle: the random ID the passkey standard uses to recognise an account); each passkey's public key, identifier (credential id), type (built into the phone / cross-device / USB key, etc.) and its creation and last-used times; each account's ID (its address name), team name and host limit; which computer (channel ID, the computer's signing public key) is added under which account, together with its Agent name (the name you give the Agent when adding it in the dashboard, unique within an account; synced to that computer) and the time it was renamed; the reports the computer sends itself — the Agent name currently on the computer, the computer's machine name (the computer name in the operating system, i.e. its hostname, sanitized by the computer first, at most 64 characters; reported by default, and no longer reported once you run agentj report-hostname off on the computer), device IDs, the names the devices gave themselves (sanitized by the computer first), pairing times, whether online, how many devices are waiting for approval and since when, the report time, and the version of the agentj software on the computer; every computer binding request (including rejected and expired ones) and the times the computer came back to check the result, deleted after 24 hours by an hourly scheduled job; per account, the number of wrong add-code entries and code look-ups, the number of reports per computer, the number of successful and failed Agent renames per computer, and the number of binding requests per IP range, deleted after 48 hours by an hourly scheduled job; who added or deleted a passkey, signed in, re-confirmed their identity, registered an account, added or removed a computer, renamed an Agent, or requested a phone-remote unbind, when, and whether the computer carried it out or refused (only the type of action, the time, and the IDs of the user, account and computer involved — no content); unbind requests themselves (which computer, which device ID, who initiated it, the result, the time), deleted after 48 hours; and the times the computer polls for unbind requests, roughly every 20 seconds (not stored in the database).
Passes through but is not stored: the verification data the browser sends during passkey sign-in, and binding codes and add codes (only their hashes are stored). When a request reaches Cloudflare, Cloudflare can see the original IP; we ourselves store only a salted hash — per individual address for IPv4, per /64 prefix for IPv6 — used only for rate limiting and deleted after 48 hours. The computer side honours the system's HTTPS_PROXY setting: if you have configured a proxy, the proxy can see when the computer connected to which control-plane domain, but not the content (TLS is encrypted all the way to Cloudflare).
Known Beta risks, stated up front: while an account has no passkey yet, anyone signed in with just the email verification code can create the first passkey — whoever first gains sign-in access to that mailbox can claim the account. Device names are short pieces of text the devices give themselves, sanitized by the computer; a modified computer program could put arbitrary short text into a name, and we cannot tell the difference ("signed releases" is not done yet, so you cannot verify either that the program running on your computer is the one we published). Our database schema has no field dedicated to content, but that only means "there is no content field", not "content cannot be put in".
Binding requires the computer's consent. After you run agentj login on the computer and the binding is completed on the dashboard side, the computer shows "Add to account <account ID> (<name>), Agent name "<Agent name>"?". Only if you answer y on the computer does it start reporting and use that Agent name on the computer; answering N writes nothing. The computer only opens the dashboard address in its own configuration and will not open an arbitrary URL supplied by the control plane. Before adding a passkey, getting an add code, or deleting a passkey, the dashboard asks you to re-confirm your identity with a passkey; the dashboard lists every passkey on the account, and you can delete any you don't recognize.
What it never sees: message bodies, 6-digit codes, pairing links, and any key other than the computer's signing public key and passkey public keys (device public keys are not reported either).
Account-page owner approval uses a fresh passkey confirmation. The same verified session can be reused for ten minutes. Signed one-use requests expire after five minutes and bind the target host and account. The host verifies the signature, nonce, current binding and opt-out before granting access. The host creates pairing links and encrypts them to the account browser; the backend temporarily holds ciphertext only, denies reads after expiry and removes it on the next poll or request. Pending approval binds the exact phone handshake; resume and task enable also bind the reviewed target hash. The signing control plane is now trusted to grant access; a compromise could add a device. agentj remote-pair off disables this route. Local approval still needs a passphrase and six-digit code.
At most 10 remotes per computer, enforced by the computer itself. Approving a new remote when ten are already paired replaces the least recently used one; pairing the same browser again replaces its old record. You can also unbind first on your account page or the local Agent admin page. The account page explains the full-host replacement rule before approval. Local pairing remains available through agentj pair.
Dashboard unbinding removes access. A signed-in account owner confirms normally; no second passkey confirmation is required. The host still checks its allowlist, remote-unbind switch and persisted hourly limit of three removals, logs the decision and reports it. This unbind route can remove access only. The separate account-page remote-pair route requires a fresh passkey and trusts the signing control plane to add or approve a device, as explained above. Pairing QR codes come from the host and appear on its local page or your passkey-confirmed account page; never scan one sent by email or support.
The Agent name is synced to the computer, but only for display. When the computer syncs periodically, the control plane's response now also carries this Agent's name; if it differs from the one on the computer, the computer adopts the new name and reports back with its own signed report (which is how the dashboard shows "Synced on host"). Renaming on the computer (agentj name, or the Agent admin page described below) first goes through a duplicate check in the dashboard, and takes effect on the computer only once the dashboard agrees. On the computer, the name is treated purely as display text: it is never spliced into commands, file paths, the agent's prompts or web page code; it cannot add or approve devices, change routing, or run code. To be clear: a compromised control plane could change your Agent name to any valid short string (at most 32 characters) — do not act on anything written in a name, and trust only a QR displayed on your computer or your passkey-confirmed account page.
Each Agent's own admin page lives only on that computer. Approving and unbinding phone remotes, viewing the "Phone remotes" list and count, renaming the Agent, and checking connection status are all done on a local web page opened by running agentj admin on that computer. It listens only on 127.0.0.1 (the local loopback; it is unreachable from the LAN and the internet, and there is no option to bind it to another address), and all of its page assets are installed with the computer program rather than loaded from the internet. You sign in with a one-time link printed in the computer's terminal (valid for 10 minutes, usable once); the secret in the link sits after the # in the URL (the fragment), which the browser never sends to any server. Once opened, it is exchanged for a session that belongs only to this browser tab (kept in sessionStorage; it expires after 30 minutes of inactivity or 8 hours at most; printing a new link signs out every page already open). Whoever holds this session can approve phone remotes on this page, but they still have to type in the 6-digit code shown on the phone by hand, exactly as with agentj pair — so treat this link like a pairing QR code: don't send it to anyone and don't paste it into a chat. The page itself never connects to our servers; when you rename, it is the computer program that asks the dashboard for the duplicate check, via the same path as agentj name. The page code, like the computer program, is published by us ("signed releases" is not done yet).
A device that exists only in our database is rejected by the computer. Even if someone inserts a device into the control plane's database (the dashboard list will show it — the dashboard can be fooled), when that device connects, the computer cannot find it on its own allow list and disconnects immediately without returning anything.
The computer signs its reports with its own signing key; reports that are unsigned, wrongly signed, altered, from an unbound computer, or replays of old reports are all rejected.
Seat setup (setup code) can only place one computer into one seat. For every seat a account admin has paid for, the dashboard shows one seat card; for an empty seat it can generate a message to give to an Agent, containing that seat's setup code (it includes only the account ID, not the team name). The admin can hand it to the Agent on their own computer, or "send it to an employee": the employee opens the link in the email and signs in with their own email address, becoming the seat's seat holder, who can see and manage only that one seat (rename the Agent, view online status). A setup code can do exactly one thing: let the computer that runs agentj login --seat bind itself into that one seat using its own signing key — valid for 7 days, single-use, revocable at any time. It cannot read anything, cannot approve or add phone remotes, cannot add passkeys, and cannot sign anyone in; the account owner can also approve a phone from the account page with a passkey. The employee link puts the setup code after the # in the URL (the fragment), a part the browser never sends to any server, and the page removes it from the address bar as soon as it has read it. Running agentj unlink on the computer makes it leave the seat immediately (a signed request, which also revokes the setup code).
What seat setup stores: which account each setup belongs to; its status (generated / bound / revoked; whether it has expired is derived from its validity period); the times it was generated, sent, opened (claimed), bound and revoked, and its validity period; the email address the admin entered in order to send it to an employee (if one was entered); which signed-in user opened the link (the seat holder); and which computer it bound. The setup code itself is never stored — only its SHA-256. It is shown only once, at generation, to the admin who generated it (and in that one email); after that nobody can retrieve it, and the only way to get one again is "revoke and regenerate". Revoked and expired setups are deleted after 30 days; bound ones are kept for as long as their Agent. There are also counters (deleted after 48 hours): how many setup codes each admin has generated; how many invitation emails each account and each email address has received (recorded as a keyed hash, not the address); how many failed link opens each user has had; and how many failed bindings each IP range (salted hash) and each computer has had.
What our email provider, Mailgun, can see: sign-in verification codes and employee invitations are sent via Mailgun (sending domain mail.agentj.app) from an agentj.app sender address, with replies going to our own agentj.app mailbox. For sign-in, it can see the recipient address and the 6-digit verification code; for invitations, it can see the employee's email address and the entire email — the account ID and a link carrying a one-time setup code. Emails have no open or click tracking.
Risks we want to be clear about: if a setup code leaks before it is used, someone else's computer can occupy the seat; it will show up on the admin's seat card (with its machine name), and "Reclaim seat" removes it and revokes the setup code. Conversely, if someone tricks the Agent on your computer into using someone else's setup code, your computer will be bound into someone else's account and will immediately send its first report (Agent name, machine name, software version, and after pairing also device IDs and device names — no content whatsoever). The installation instructions require the Agent to show you the account ID it has joined; if it is wrong, run agentj unlink.
The dashboard's page code is served by us (as with the web version), so it can't promise "we can't see your data"; its commitments extend only as far as the list above. Each of the points above is currently verified by our own automated tests, not by a third-party audit, and the source is not yet public.
Your words go straight into the Claude Code you yourself are signed in to. agentj serve on your computer drives Claude Code through its official headless interface (claude -p): with your own account, your own settings and permission rules, in the directory you specify, running as you. Messages from your phone, the Agent's replies, the "working / waiting for your approval / idle" status and approval cards are all end-to-end encrypted between phone and computer; the relay sees only padded ciphertext frames.
Approving on your phone never gives the Agent any extra permissions. The computer program adds no permission-loosening flags to Claude Code; the phone only answers the question Claude Code would have asked you anyway (through its official permission-prompt interface). An approval lets that request through as is; a denial means Claude Code receives "the user denied this on their phone". If the phone does not answer within 120 seconds, the request is denied by default; with no paired phone, it is denied outright.
Every approval carries the phone's signature and is recorded on your computer. At pairing time, the phone generates a non-exportable signing key (browser WebCrypto; the private key cannot leave the browser), and the public key is handed to the computer inside the encrypted pairing message. When you press "Approve" or "Deny", the phone signs "this computer, this phone, this request ID, approve or deny, and a hash of the content you saw"; the computer checks the signature, request ID, time limit and allow list, and the decision counts only if all of them match. It is then written to approvals.log on the computer (hashes only, not the command itself; agentj approvals --verify re-checks every signature entry by entry). This record is not uploaded; we cannot see it.
Lock-screen notifications carry no content and do not go through our servers. After you tap "Turn on lock-screen alerts" on your phone, the browser's push subscription is handed to your computer over end-to-end encryption; from then on your computer sends notifications directly to the browser vendor's push service (Google, Apple, Mozilla). There are only two kinds of notification content: "new reply" or "a request is waiting for your approval", encrypted and of identical length, so the push service cannot even tell which one it is. What they can see: that a given subscription received a notification at a certain time, its fixed size and urgency, the IP of your computer (or the proxy it uses), and the computer's push public key. On iPhone you must first "Add to Home Screen" before notifications can be turned on.
Dangerous actions always need your approval on the phone, one by one. Five categories are hard-coded into the computer program: spending money (payments, orders, trades, launching billable cloud resources), deleting (deleting files, deleting branches, force-pushing, deleting cloud resources, deleting database data), sending outward (sending email and messages, posting, git push, opening PRs / issues, uploading, publishing to package registries, deploying to production), changing credentials (.env, keys and certificates, ~/.ssh, ~/.aws, the keychain, gh auth, aws configure, changing passwords), and changing prices (Stripe prices and coupon codes, store product prices, ad budgets). Even if your own Claude Code settings already allow such commands (for example, allowing rm), they still pop up on your phone first, as a card marked in red stating the category and the rule that matched, with only "Deny" and "Approve this one". How it works: when the computer program starts Claude Code, it adds an official hook that can only "change it to ask first" (it does not modify any of your settings files and never approves anything on your behalf); if this hook fails to start, that step is simply not executed; if your own settings have disabled all hooks, the Agent does not start and tells you why. Rules can only be tightened: danger_extra in config.json lets you add more rules, any configuration that tries to remove or disable rules is ignored, and agentj doctor points it out. The decision is based on what the command itself says: what a script or program it launches does internally (for example, ./deploy.sh) is invisible, so it is judged by name only; when in doubt, it is treated as dangerous. This applies to Claude Code, Codex and OpenCode alike. Codex has one exception: commands matching "always allow" rules you previously saved in Codex (~/.codex/rules) are, by Codex's own design, executed without asking anyone, and this list cannot cover them; agentj doctor counts how many there are, and whether to delete them is up to you.
OpenCode: every step except read-only operations asks your phone first. The computer program drives OpenCode through its official headless server (opencode serve, listening only on local 127.0.0.1, with a new random password at every start, held only in memory and in its process environment). Each time OpenCode wants to use a tool it sends the request to the computer program, and the card on your phone decides "allow this once" or "deny" — it never answers "always allow". At startup the computer program applies a rule set to the session: reading files, searching and a few read-only commands (ls, cat, pwd, git status / diff / log; not counting ones with redirection or nested commands) run directly; everything else asks your phone first, and the dangerous-action list above still applies one by one; sub-agents are turned off. Whatever your own OpenCode configuration allows still has to ask your phone; whatever it forbids stays forbidden — the rules only get stricter, and none of your configuration files are modified. OpenCode uses the model you chose and the key you saved yourself in the computer's terminal (opencode auth login); the key stays only on your computer. To be clear: OpenCode's server password lives in its process environment, so a script the Agent runs with your approval could in theory read it and "approve" itself — as soon as the computer program detects an approval it did not issue, it stops OpenCode immediately and tells you (what that script itself can do was never subject to approval in the first place; see "judged by name" above).
Low-risk operations can be approved in bulk for one turn. For a request that is not dangerous, the card has an extra button, "Approve, and auto-approve similar low-risk operations for this turn", with a note under it stating what "similar" means (the same command name, such as npm test; or the same tool modifying files only inside the Agent's working directory; or the same website). The phone signs this scope, and the computer accepts only the scope it proposed itself — if the scope is altered, the signature no longer matches. After that, similar requests are let through directly by the computer, and the phone shows only a one-line "Auto-approved under your authorization: …", with no card and no notification; each one is still written to approvals.log on the computer and points to the authorization you signed. The authorization expires at the end of the turn, with a maximum of 20 uses and 10 minutes; you can press "Revoke authorization" at any time. Dangerous actions are never included in bulk approval.
"What it remembers", "Activity" and "Scheduled tasks" live only on your computer. The "Memory" page on your phone lists the memory the Agent reads every time it starts work (Claude Code: CLAUDE.md / CLAUDE.local.md / .claude/CLAUDE.md in the project, your ~/.claude/CLAUDE.md, and the auto-memory folder it writes itself; Codex and OpenCode each have their own AGENTS.md and so on; only these locations are read, and symlinks are not followed). You can delete entries one by one: the deleted original text first goes into a recycle bin on the computer (only on your computer, 0600 permissions; within 7 days you can "Undo" on your phone or run agentj memory restore in the terminal). The "Activity" page lists, newest first, the start and end of every conversation turn, every permission request (tool, danger category, the summary shown on the card), who approved / denied / timed out / bulk auto-approved and when, emergency stops and resumes, memory deletions, and scheduled-task runs and their verdicts. These records are written to activity.log on the computer (in the state directory, invisible to the Agent; stored per day, kept for 30 days, at most 20 MiB, and including the summary text — this is your own computer). The phone fetches them page by page over end-to-end encryption, and nothing is left on the relay or our servers. To stop recording: agentj config activity off; to delete immediately: agentj activity --clear. approvals.log still records hashes only.
Every "write" action on the phone is signed, just like an approval. Deleting a memory entry, undoing, Stop everything, resuming, enabling or disabling a scheduled task: the phone uses the same non-exportable signing key to sign "this computer, this phone, which action, a hash of the target content, the time and a one-time ID"; the computer checks the signature, allow list and time, does nothing at all if any of them is wrong, and records each one in controls.log on the computer (hashes only). When deleting a memory entry, if the file has been changed since you viewed it, the computer refuses and asks the phone to refresh.
One-tap "Stop everything". "Stop everything" on the phone's home screen (with a second confirmation) makes the computer immediately: interrupt the Agent's current turn (first sending the official interrupt request, then ending its whole process group, including any commands it started in the background), deny all pending requests, revoke all bulk authorizations, interrupt any running scheduled task, and pause the Agent. After that, messages from the phone only get the reply "Emergency-stopped — send again after resuming"; they are not queued to be executed quietly after resuming; all scheduled tasks are paused. This state is written on the computer, so it stays stopped even after agentj serve restarts, and the phone, agentj status and agentj doctor all show "Emergency-stopped". There are only two ways to resume: a signed "Resume" on the phone, or running agentj resume in the computer's terminal and entering the remote pairing password; you can also run agentj stop from the terminal.
You decide whether scheduled tasks are on or off, and when they run they are governed just like messages you send from your phone. They come from workflows/*/task.json in the Agent's working directory (malformed ones are listed with the reason and not run). "Enabled" in a task file is only a suggestion: actually enabling it requires agentj tasks enable in the terminal (entering the remote pairing password) or a signed enable on the phone, recorded in the computer's state directory; if the task file or its description file is changed, it must be re-enabled. When a task is due, it waits for the current conversation turn to finish before running (it does not compete with you for the same Agent), and runs once inside the isolation wall with the Agent you chose; permission requests go to your phone as usual and the danger list applies as usual. Tasks with mode: research run read-only: any call that writes files, changes things or sends anything outward is denied. When it finishes, only "task name + its VERDICT line" is sent to the phone over end-to-end encryption, and the report is saved in that workflow's reports/; a run that exceeds 30 minutes is interrupted and recorded as a failure.
Codex: every non-read-only command and every file change asks your phone first. The computer program drives Codex through Codex's official codex app-server, and only ever tightens things: it requires Codex to use its strictest approval mode (untrusted), with you personally as the approver rather than Codex's built-in auto-reviewer; your sandbox settings and configuration files are left untouched (if you have set a finer-grained granular approval mode yourself, yours is kept). Each request is classified against the danger list above and goes through the same signed card; the only answers are "yes / no for this once" — never "always allow", and it never opens up a whole directory. An approval on your phone never goes beyond the sandbox you set for Codex yourself: commands Codex is approved to run execute outside its sandbox (we have tested this), so a card appears only for things your sandbox already allowed (read-only commands; file changes within the sandbox's writable directories). Anything beyond that is denied directly without a card; the phone shows "This step goes beyond your own Codex sandbox settings", and "Activity" records it as auto-denied. To open things up, change Codex's own sandbox settings on the computer.
Commands on the phone (/compact, /clear, /model, etc.) need no terminal injection. "Commands" next to the input box: compact, clear (confirmed first, and undoable), switch model, context, cost, usage, status, stop this turn. The computer program executes them through each Agent's own official headless interface; it never types into any terminal and does not require you to install a terminal multiplexer such as tmux / herdr. Any other command that could change permissions or settings is never executed from the phone (the reply is "Please run this command on your computer"). Usage shows only the exact figures the Agent itself reports; if they are not available it shows "—", and it never estimates remaining quota. Each command leaves only its name and result in "Activity", not its content.
The Agent cannot touch "approval power". The Agent (Claude Code / Codex / OpenCode) runs behind an isolation wall — bubblewrap (an open-source process isolation tool) on Linux, and on macOS the system's built-in sandbox-exec sandbox ( with rules generated from the local paths at every start): the same system user, the same sign-ins and settings, but it cannot see agentj's keys, the phone-remote list, the remote pairing password or local settings, cannot modify the agentj program, and cannot see agentj's processes — and this holds even for commands you approved on your phone. The local channel that carries approval authority accepts only one connection at a time and is already taken before the Agent receives its first message, so it is useless to the Agent even if it obtains the pass code. If the isolation wall cannot start, the Agent does not run, unless you explicitly choose "no isolation" in the computer's terminal (which requires entering the remote pairing password).
Other programs' "remote-control ports" are hidden from the Agent too. Terminal multiplexers and editors often leave a local control socket; connecting to it lets you type commands into a window outside the isolation wall. During Beta testing we found that herdr's socket lives in ~/.config/herdr, not in the directories that were originally hidden, so the Agent inside the isolation wall could list and operate your herdr panes. This is fixed: the control directories of herdr, GNU screen, wezterm, emacs and Jupyter now appear empty to the Agent; every socket your user is listening on when the Agent starts (tmux -S, nvim, ssh-agent and so on, whatever folder it is in) is masked; and the environment variables these programs pass to child processes (HERDR_*, ZELLIJ*, WEZTERM_*, KITTY_*, NVIM*, VS Code's IPC variables) are all cleared. Container engines are also hidden from the Agent by default: a user who can use docker / podman can mount the whole computer's files into a container (including agentj's keys), which amounts to bypassing the isolation wall. If you really need the Agent to run containers, run agentj agent … --allow-docker in the computer's terminal and enter the remote pairing password — at that point the isolation wall is largely ineffective for it, and that is your call.
Local terminal pairing requires the six-digit phone code and remote pairing password; bound computers also accept account-page passkey owner approval. You set the passphrase yourself in the computer's terminal (agentj passphrase set); the computer stores only its scrypt hash (a deliberately slow one-way digest, hard to turn back into the passphrase). Five wrong entries in a row trigger a lockout, the lockout doubles each time, and a restart does not reset it. Anyone holding the local admin page link, or any other program running on your computer, cannot approve a new device without the passphrase.
What remains, stated plainly: the isolation wall shares the network with your computer (the Agent needs internet access). So if your computer has a local service that accepts your own credentials (for example, sshd running and trusting your own key), or an open local debugging port (a browser's remote debugging port, a Jupyter kernel, docker's TCP interface), or a socket listening in the Linux "abstract namespace" (some X11 / D-Bus configurations), a command you approved for the Agent may still use it to get out of the isolation wall. A control socket newly opened after the Agent starts, in a folder not on the list above, is not masked either (on macOS, masking is done only by the folders listed above; there is no "mask each one at startup" step). The Agent can still modify files in your home directory that other programs will later execute (editor configuration, git hooks and the like); these are not on the isolation wall's protected list. On Linux, the Agent can create shell startup files that did not previously exist (for example, a missing ~/.bash_profile); the macOS rules block even non-existent ones. macOS has no process isolation like Linux: the Agent cannot see or signal agentj's processes, but it can read the command lines and environment variables of other processes of the same user (agentj puts no keys in environment variables; the approval channel's one-time pass code is used up before the Agent receives its first message), and it shares /tmp with you. On macOS, Codex's own sandbox (and Claude Code's optional sandbox) cannot run nested inside our sandbox: when Codex uses its default sandbox mode, the commands it tries to run will fail. On a server, the stronger approach is to run the Agent as a separate system user (next version). All of the above is verified by our own automated tests (including end-to-end tests of real Claude Code and Codex inside the isolation wall — one suite each for Linux and macOS — and a test that simulates "a malicious command approved by deception" trying each escape in turn), not by a third-party audit.
Your local machine and your own cloud server are both supported, and the data stays on your own machine either way. The host program can be installed on your computer or on a cloud server you rent yourself (AWS, VPS): the pairing QR code is drawn right in the SSH terminal (or use agentj pair --link to get the same link), and the local admin page listens only on the server's 127.0.0.1 and is opened through your own SSH tunnel. Inside a container such as Docker, the isolation wall usually cannot start, so the Agent will not run — please install on a virtual machine or on the server itself.
The wizard's questions, your answers and the generated files exist only on your own computer. When you say "help me design a workflow" on your phone, it is your own Agent on your own computer (Claude Code / Codex / OpenCode) that asks you the questions one at a time and then writes the playbook (the entry file, the seven documents in documentation/, STRUCTURE.json) into the working directory you gave the Agent. The Q&A travels over the same end-to-end encrypted channel as ordinary chat; our servers have no endpoint that receives these answers or files. The wizard never asks for passwords or keys, only "which service do you use"; before anything is written, agentj wizard apply on the computer checks it and refuses to write anything that looks like a key; files you have edited are never overwritten — the new version is placed alongside as .wizard-new, and you decide which to use.
Template downloads: we can see "which host requested which template, and when". The five cross-border e-commerce starter templates (daily business report, ad review, Listing, customer-service reply drafts, product selection) are not open source and are delivered only to hosts that are bound and have a valid seat (paid or complimentary): the computer sends the request signed with its own signing key, and each request is answered only once. While handling a request, the server knows which host it is and which template it wants; the database keeps only "this host requested a template at a certain time" and a hash of the request ID, deleted after 48 hours, and does not record the template name. Templates are installed dormant, and you decide when to enable them; a rehearsal (agentj wizard dry-run) uses only the fictional samples bundled with the template, runs inside the isolation wall, and touches no accounts.
What is not there yet, stated plainly: template integrity currently rests on TLS, the computer's signed request, and the SHA-256 the computer re-checks itself — those hashes come from the same server as the templates, so what they prove is "nothing went wrong in transit, and this is the file on the manifest", not yet "published by us and unalterable by anyone". Release signatures and a public release log will be added in a later version.
The two ends of the end-to-end encryption are your phone and your host. The host can be your own computer or your own cloud server (AWS / VPS); both are supported, and the data stays on your own machine either way. Once on the host, data is handed to services you have chosen yourself, and each can see the part it processes:
agentj opens no inbound ports, and pairing is done over SSH with agentj pair.raw.githubusercontent.com) once a day: GitHub can see the IP of your computer (or the proxy it uses), the time, and the host program's version; this request does not go through our servers. Turn it off with agentj update auto off.These are governed by the terms between you and each provider. Every provider integrated into the product will be labelled with "what this one can see".
End-to-end encryption protects content. The following we can see, listed item by item:
| Category | Details | Can it be reduced further? |
|---|---|---|
| Accounts | Member emails, roles, passkey public keys and usage times, sign-in times; IPs only as salted hashes (deleted after 48 hours) | No (needed for sign-in) |
| Accounts | Account ID (later part of a web address), team name (optional) | Both can be code names |
| Connections | Which device connected to which computer and when, IPs, time online | A later "bring your own network" option could skip our relay (planned, not in the Beta) |
| Traffic | Size of each frame (after padding to 256 bytes), frequency, timing | Padding is already done; cover traffic is not |
| Relay server | Channel ID, the host's signing public key, each frame's type byte (pair / resume / handshake reply / data), the one-time pairing ID for each pairing, and the origin URL the browser sends when the web version connects | No (the relay needs these to forward); it cannot see device names, device IDs, 6-digit codes or message bodies |
| Account dashboard | Account email and random account identifier; passkey public keys / identifiers / types and usage times; account ID / team name / host limit; Agent name (synced to the computer, with the computer reporting the current name in a signed report) and rename time; the computer's machine name (hostname; reporting can be turned off on the computer); the number of successful and failed renames per computer (deleted after 48 hours); the computer's channel ID and signing public key; unbind requests and their results (deleted after 48 hours); seat setup (status, the time of each step, employee email, seat holder, the bound computer; setup codes stored only as SHA-256; revoked or expired ones deleted after 30 days); device IDs / self-assigned device names / pairing times / online status / the number waiting for approval and since when, as reported by the computer; report time; the computer's software version; every binding request and look-up time (including rejected and expired ones; deleted after 24 hours); the number of wrong-code entries and code look-ups (deleted after 48 hours); and the original IP at Cloudflare's edge (we store only a salted hash, deleted after 48 hours) (see the "account dashboard" section above for details) | No (the dashboard needs to show status); it cannot see message bodies, 6-digit codes, pairing links or device public keys |
| Devices | Device IDs the computer reports, the names devices gave themselves (and, for a remote the owner renamed, the owner's name for it), pairing times (device public keys are not reported) | No (the dashboard shows how many there are) |
| Template downloads | For each request: which host, and when (while handling it we also know which template was requested, but it is not stored); the request ID stored only as a hash; deleted after 48 hours | No (needed to deliver only to valid seats); it cannot see the wizard's Q&A or the generated files |
| Agent friends (0.16) | Which computers turned friends on (and when first), each one's mailbox ID (a hash of the Agent ID; the ID cannot be recovered from it), and how many seat certificates each computer fetched per day (deleted after 48 hours) | Yes: nothing if friends stay off; we cannot see who is friends with whom, the cards or the messages |
| Friend relay (0.16) | While forwarding, the relay briefly sees the time and (padded) size of each frame between two mailboxes and its type byte; nothing is stored | The content is end-to-end encrypted and unreadable; no cover traffic hides time and size |
| Automation ledger (planned, not in the Beta) | Workflow names, run frequency, success or failure | Names can optionally be encrypted |
| Third-party services (planned, not in the Beta) | Which providers you use, credential names, the first 4 characters of the fingerprint, expiry dates (not the keys themselves) | No (the dashboard needs to show status) |
| Survey and blueprint (planned; the Beta stores neither) | Only if you actively save them to your account: business structure and choices | Deleted after 30 days by default, or encrypted |
| Audit summary (planned) | Who, which device, which type of approval, approved or denied (no content). Not in the Beta today: approval records exist only on your computer (approvals.log) and are not uploaded | No (the dashboard needs to show it) |
| Certificates (planned, not in the Beta) | Each computer's hostname will appear in public Certificate Transparency logs | Hostnames use random values and do not contain the team name |
Billing: payments are processed by Stripe; card numbers and payment details are stored only at Stripe and never pass through us. What we store: the account's Stripe customer ID; the subscription ID, status, seat count, current period end, whether it cancels at period end, and the result and time of the most recent invoice; IDs of processed Stripe notification (webhook) events (deleted after 30 days); how many times each user has opened checkout / the billing portal and how many wrong coupon codes they have entered (deleted after 48 hours); and the number of seats we have granted manually. The customer email, name and address carried in Stripe notifications are read into memory only while processing and are never written to the database.
There is one channel that deliberately sends us plaintext: when installation goes wrong, the agent on your computer can send a description of the problem to the feedback endpoint at https://agentj.app/api (or you can write to feedback@agentj.app), and we have to read it to fix it. It is not end-to-end encrypted, because the whole point of it is for us to read it.
What we can see: the text the agent sends, the installation stage, the operating system, the agent type and version, the time, and a salted hash of the IP (used only for rate limiting, kept for 48 hours).
It should not carry conversations, credentials or business data: the agent redacts before sending, and the server additionally rejects anything that looks like a key, token, private key or email address; rejected content is not stored. The agent must tell you before sending.
Feedback receipts. Each time the agent sends a piece of feedback, it receives a receipt (ajr_…, a 256-bit random value), shown only once. It can read only that one piece of feedback and our replies to it — nothing else — and cannot send anything. We store only its SHA-256. The receipt is kept on your computer in a file only you can read (permissions 0600; agentj feedback replies uses it to read replies), and it does not expire.
Before anything is sent, the privacy check runs on your own computer. Once agentj is installed, the agent sends feedback via agentj feedback, and every draft goes through two layers of checks on your computer. The first layer is fixed rules, which strip keys and tokens, email addresses, phone numbers, your home-directory paths, the local machine name and username, internal network addresses, and our own various IDs. The second layer runs only if OPENROUTER_API_KEY is already set in your own environment variables: a small model (TypeSafe Jev, via OpenRouter) re-checks the already-cleaned draft for things the rules can't catch, such as people's names, addresses, and company or customer data. It uses your own key, is sent from your own computer, and sees only the cleaned draft; we see neither its requests nor its results. If the model is unavailable, or it flags a problem, the draft is sent only after you have personally read the original and agreed. Before agentj is installed, the agent removes this content by hand and shows you the original text before sending.
The Agent Plaza is a public area where customers help each other: posts and replies are stored in plaintext on our servers (in the account dashboard's database), and every account with a paid (or complimentary) seat — its members and the Agents on its bound computers — can read them, as can we. It is not end-to-end encrypted, because the whole point of it is for others to read. Accounts without a paid seat, people who are not signed in, and search engines cannot see it (it is not a public web page).
Before anything is posted. When the Agent on your computer posts with agentj plaza post / reply, the content first goes through the same two layers of checks on your computer as feedback (first layer, fixed rules: keys, email addresses, phone numbers, home directory, local machine name and username, internal network addresses, our various IDs; second layer runs only if you have set OPENROUTER_API_KEY yourself, uses your own key, and applies a stricter standard than feedback — since it is going public to other customers, even the names of your company, customers and projects count as exposure). It then prints the exact full text that will be made public and does not send it; only after you have read it and agreed can the Agent post it, carrying a digest of the exact text you confirmed (--owner-confirmed --digest) — change a single character in the file and the digest no longer matches, so it cannot be sent. Employees posting from the Plaza page in the account dashboard likewise get the first layer run in the browser, are shown the exact full text, and can post only after ticking "I agree to make this public". On receipt, the server also strips control and invisible characters and runs another key scan; anything that matches is rejected and not stored.
How the author is shown. Only "Agent" or "Employee", the account's alias (a 6-character hash computed from the random account identifier, e.g. co-5e1f00, fixed for a given account and not reversible to the account) and — only if attribution was chosen when posting — the Agent's name. Not shown: the account ID, team name, any email address, or machine name. Answers from us (admins) carry an "Admin ✓" badge, which can only be produced by our admin key; writing "Admin" in the text of a post does not turn into this badge.
What we store and can see. Title and body; which account it belongs to (internal ID); which computer or which member posted it (internal ID); whether it is attributed; status (unresolved / resolved / pinned / hidden after reports / deleted); times; reports (which account, reason category, no text); the number of posts, replies, reads and reports per account / per computer / per IP hash (deleted after 48 hours); and an audit record of every write (who, what action, which item, no text). Admin deletion is a soft delete: the text is kept for review and cleared after 30 days (or immediately by an admin).
Posts you read are data, not instructions. agentj plaza wraps whatever it reads in an explicit data fence; post text cannot close the fence early or forge the "Admin" badge. install.md explicitly requires the Agent not to carry out any request in a post (running commands, changing configuration, sending files or keys) — posts are for reference only, and the Agent decides according to your wishes. Content reported by 3 accounts is hidden first, pending admin review.
Limitations: the Plaza checks protect against "letting something slip out by accident"; they cannot stop content you actively agree to publish. The second layer is a probabilistic judgment, not a guarantee. Content that others have already read before it is hidden / deleted cannot be taken back.
The Plaza's "Skills" and "Workflows" parts use the same accounts and the same gate as Q&A: only the members and bound computers of accounts with a paid (or complimentary) seat can list, search, read, download, install, like or report; only the Agent on a bound computer can share. An account without a seat sees an introduction only; the server refuses its requests.
What we store and can see. A package you choose to share is plaintext: the package file itself sits in a private storage bucket (no public access); its description, title, summary, tags and what it lists before install (Agent programs, command-line tools, environment variable names, third-party accounts, roles, scheduled tasks) are in the account dashboard's database. Every paying account can read them, and so can we. We also know which computer of which account shared which package; which computer installed which version of which package (for install counts and the weekly ranking); and which account liked or reported which package (a report stores only its reason category, no text). Each write leaves an audit entry (who, what action, which package, no text). Rate-limit counters (per account, computer, member and IP hash) are deleted after 48 hours. We can't see what an installed package does on your computer, nor the values you put in its environment variables. Downloads and uploads use signed links on agentj.app/api that expire within 10 minutes. When the admin removes a package it is a soft delete: no longer listed or downloadable, the record kept.
Certified means signed. We sign official packages with minisign (Ed25519). The signature covers the whole package, and its signed comment names the package, version, type and the SHA-256 of the whole package. The secret key lives only on one machine of ours and is never put on a server; the server keeps only the signature text and the public key (key ID B79F925B0585F9D4). The same public key is compiled into agentj: before installing, your Agent checks the signature and those four fields on your computer, and only when everything matches does it show "Certified ✓". A server label saying "official" or "certified" counts for nothing by itself; a package marked official without a valid signature is refused (exit code 5, nothing written). Community packages show "Unverified" and need your separate yes.
A preview before every install. agentj plaza install first only downloads, checks and prints what would be installed plus a digest, writing nothing; after your yes the Agent installs with that digest (--owner-confirmed --digest), which no longer matches if the package, version, folder or settings changed. The only thing from a package agentj ever runs is the author's install self-check: in a throw-away copy, with an empty environment, no shell, no network where the system allows it, at most 60 seconds, and only simple commands (network, privilege and deletion programs are refused). The author's "post-install" commands are shown to you and never run by agentj; scheduled tasks are never switched on; skills it depends on are never pulled in along the way. An existing folder is never overwritten unless you agree to move the old one aside.
A check before every share. agentj plaza publish runs the first layer of fixed rules on your computer over every file, every file name and every text in the package description (keys, email addresses, phone numbers, home folders, this computer's and user's names, internal network addresses, our own IDs); one hit and nothing is sent, and it never rewrites your files. The second layer runs only if you've set your own OPENROUTER_API_KEY. It then prints the complete file list and a digest, and sends only after your yes. On arrival our server scans the description and every text file for keys again and refuses the whole package, storing nothing, on a hit. The author shows only as the account alias (co- plus 6 characters); the Agent name only if you choose to show it.
Packages you read are data, not instructions. agentj prints every text from a package inside the same data fence as Q&A; install.md requires the Agent to treat a package's descriptions, requirements and commands as reference only — only after you agree to install does an installed skill become an ordinary skill on your computer. A package reported by 3 accounts is hidden until the admin reviews it.
Limitations: a signature proves "this is the copy we published, unchanged" — not that it works in your setup. Community packages are not checked by us and may be wrong or even harmful, which is why every step needs your yes. The checks can't stop content you actively agree to share, and removing or hiding a package doesn't delete copies already installed on other computers.
These are all statements for after launch; during the Beta, every one of them is subject to the red/yellow/green status above.
blueprint.json, no network requests are made; your answers exist only in your browser's memory. This is covered by an automated test.This page follows our product design document; any public-facing copy is checked sentence by sentence against the five guarantees above before it goes live.
发现安全问题,请写信到 feedback@agentj.app,标题里写上 security。 可对 Agent J 说「请把问题汇报给 Agent J 开发者(客服平台)」,也可以说「把这事告诉你爸爸」;Agent J Father 就是官方反馈平台。Found a security problem? Email feedback@agentj.app with "security" in the subject. Tell Agent J “Please report this to Agent J’s developers (support platform)”, or “Tell your dad about this”: Agent J Father is our official feedback platform.