跳到主要内容

Brabo API (0.1.0)

下载 OpenAPI 规范:下载

Brabo API。除了四个明确记录了不同 content-type 的端点(两个 SSE 端点、指标端点,以及会重定向的 OAuth 回调)之外,每个端点都返回 JSON。

认证

访问令牌是一个 15 分钟有效的 EdDSA JWT,通过 Authorization: Bearer <token> 出示。公钥位于 GET /.well-known/jwks.json。

refresh 不是 JWT:它是一个不透明令牌,存放在 httpOnly cookie(brabo_refresh、Path=/auth、SameSite=Strict)中, 从不出现在任何响应体中。POST /auth/refresh 和 POST /auth/logout 读取该 cookie,并要求 X-CSRF-Token 头 与 brabo_csrf cookie 一致。

轮换是强制的。 每次 refresh 都会消耗所出示的令牌并 签发另一个。重复出示已被消耗的令牌是被盗的特征, 会撤销整个令牌族——包括合法的会话。一个 同时发起两次并发 refresh 的客户端会把自己踢下线;请只保留一个进行中的 调用。

/internal/* 路由是 api ↔ engine 之间的接口,位于 JWT 之外: 它们要求带有共享机密的 X-Brabo-Service-Token 头。 用户令牌打不开其中任何一个。

错误

NestJS 默认格式:{ "statusCode": number, "message": string | string[], "error": string }。

代码 何时
400 请求体无效——ValidationPipe 以 whitelist 和 forbidNonWhitelisted 运行,因此未知字段也会失败
401 没有令牌、令牌已过期或凭据无效
403 已认证但没有 RBAC 要求的角色,或服务令牌错误
404 资源不存在或对调用方不可见
409 状态冲突——无效的会话状态转换、资源已存在
429 速率限制或渐进式锁定

认证路由对不存在的邮箱、错误的密码和被锁定的账户 刻意给出无法区分的响应:相同的响应体、相同的状态码、相同的 耗时。这正是防止账户枚举的手段,而不是诊断上的 缺陷。

速率限制

基于 Postgres 的滑动窗口:每 60 秒每个用户 300 次请求、每个 IP 600 次请求, 可配置。@Public() 路由和服务路由豁免——保护 /auth/* 的是渐进式锁定,而不是速率限制。

认证

访问令牌的公开验证密钥

正常运行时一个密钥;AUTH_JWT_SECRET 轮换期间两个。

响应

响应示例

Content type
application/json
{
  • "keys": [
    ]
}

进行身份验证并签发 access + refresh 令牌对

不存在的邮箱、错误的密码和被锁定的账户都返回完全相同的 401 响应——相同的响应体,相同的状态码。

Request Body schema: application/json
required
email
required
string
senha
required
string

响应

请求示例

Content type
application/json
{
  • "email": "fulano@brabo.dev",
  • "senha": "correct horse battery staple"
}

响应示例

Content type
application/json
{
  • "accessToken": "string",
  • "expiresIn": 900,
  • "locale": "pt-BR"
}

撤销所出示 refresh 所属的整个令牌族

始终返回 204,即使令牌未知——在此返回 401 将成为令牌有效性的探测口。

响应

接收社交登录的 OAuth 回调

成功时跳转到 WEB_ORIGIN/ 并已设置会话 cookie;失败时跳转到 WEB_ORIGIN/login?oauth_error=1,不说明原因。

path Parameters
provider
required
string
枚举: "github" "gitlab"
query Parameters
code
required
string
state
required
string

响应

重定向到 OAuth 提供商进行社交登录

state 以其自身专用用途经 HMAC 签名——绝不使用 git 连接到项目流程的签名(见 ADR 0084)。

path Parameters
provider
required
string
枚举: "github" "gitlab"

响应

轮换 refresh 并签发新的令牌对

所出示的 refresh 会被消耗。重复出示已轮换的令牌会撤销整个令牌族并记录一条安全事件——即使原因只是客户端重复提交。

响应

响应示例

Content type
application/json
{
  • "accessToken": "string",
  • "expiresIn": 900,
  • "locale": "pt-BR"
}

创建账户并发送验证邮件

无论是新地址还是已注册地址都返回 202——响应不会透露账户是否存在。第二种情况下不会创建任何内容,地址所有者会收到通知。

Request Body schema: application/json
required
email
required
string

账户的邮箱。

senha
required
string >= 12 characters

密码。至少 12 个字符;不要求大写字母、数字或符号。

nome
string

响应

请求示例

Content type
application/json
{
  • "email": "fulano@brabo.dev",
  • "senha": "correct horse battery staple",
  • "nome": "Fulano de Tal"
}

响应示例

Content type
application/json
{
  • "message": "If the address is available, we've sent an email."
}

请求密码重置链接

无论地址已知还是未知都返回 202。这也是从 Keycloak 导入且尚未设置密码的用户所走的路径。

Request Body schema: application/json
required
email
required
string

响应

请求示例

Content type
application/json
{
  • "email": "fulano@brabo.dev"
}

响应示例

Content type
application/json
{
  • "message": "If the address is available, we've sent an email."
}

根据令牌设置新密码

撤销该用户的所有会话。不签发令牌:重置密码的人会被引导去登录,这样邮箱被攻破并不等于一步就接管了账户。

Request Body schema: application/json
required
token
required
string

通过邮件收到的一次性令牌。

novaSenha
required
string >= 12 characters

响应

请求示例

Content type
application/json
{
  • "token": "string",
  • "novaSenha": "another pretty long passphrase"
}

使用一次性令牌确认邮箱

Request Body schema: application/json
required
token
required
string

通过邮件收到的一次性令牌。

响应

请求示例

Content type
application/json
{
  • "token": "string"
}

gate

活跃 gate 的注册表

流程 gate 的声明式索引(ADR 0054)。界面从这里推导存在哪些步骤以及每一步由谁判定,而不是在代码中重复这份列表——过去正是这样在无人察觉中过时的。

Authorizations:
bearer

响应

响应示例

Content type
application/json
{
  • "version": 1,
  • "gates": [
    ]
}

恢复一个被暂停的 gate 周期

停滞超过 2 小时的 gate 周期会被暂停,而不是自行重启(ADR 0207)。这是恢复它的人工操作。

Authorizations:
bearer
path Parameters
projectId
required
string
taskId
required
string
gate
required
string

响应

响应示例

Content type
application/json
{
  • "ok": true
}

git

接收 OAuth 返回并重定向到 Web 应用

之所以公开,是因为到达这里的是用户的浏览器,从提供商跳转而来,没有 api 会话。但它并非不受限制:state 经 HMAC 校验,没有有效的 state 调用会被拒绝。从不返回 JSON——始终重定向,因为在浏览器导航中显示原始错误体体验极差。

path Parameters
provider
required
string
枚举: "github" "gitlab"
query Parameters
code
required
string
state
required
string

响应

为文件的每一行标注最后修改它的提交

为已声明的 blame 待办项(PHASE 26b)打基础——逐行标注编辑器的界面尚不存在。当文件超过标注行数上限时,truncated 会发出提示。

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
path
required
string

要标注的文件路径。

ref
string

分支、tag 或 sha。缺省时使用仓库的默认分支。

响应

响应示例

Content type
application/json
{
  • "ref": "dev",
  • "path": "apps/api/src/main.ts",
  • "lines": [
    ],
  • "truncated": false
}

列出带 ahead/behind 和关联的打开 PR 的分支

为丰富的下拉菜单(PHASE 26b)打基础——目前 ref 选择器是普通文本框。ahead/behind 相对于仓库的默认分支;提供商无法计算时为 null(诚实的降级,而非错误)。它不是 listBranches(Gitflow 引导使用的那个)——而是一个独立的操作,因为丰富信息需要为每个分支额外调用一次提供商。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "items": [
    ],
  • "truncated": false
}

返回文件内容

UTF-8,超过字节上限时截断并带 truncated: true。逃出项目文件夹的路径会被 RN-095 的中央检查以 400 拒绝——绝不用 404,那会招来探测。

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
path
required
string

文件路径。

ref
string

分支、tag 或 sha。

响应

响应示例

Content type
application/json
{
  • "ref": "dev",
  • "path": "apps/api/src/main.ts",
  • "content": "import { NestFactory } from '@nestjs/core';\n",
  • "truncated": false,
  • "bytes": 1284
}

列出仓库的 PR/MR

为可导航列表(PHASE 26b)打基础——目前 diff 只能通过已知 id 访问(例如从 Approvals 进入);此路由解决了无需记住 id 也能找到它的问题。当列表超过单次调用上限时,truncated 会发出提示。

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
state
string
枚举: "open" "merged" "closed"

缺省时列出所有状态。

响应

响应示例

Content type
application/json
{
  • "items": [
    ],
  • "truncated": false
}

返回 PR 的 diff,已在各提供商之间统一格式

patch 为 null 用于区分提供商没有交付文本(二进制文件或补丁过大)与文本返回为空这两种情况。把两者混为一谈,界面就会说一个已更改的二进制文件没有变化。当文件列表超过上限时,truncated 字段会发出提示。

Authorizations:
bearer
path Parameters
projectId
required
string
pullRequestId
required
string

响应

响应示例

Content type
application/json
{
  • "pullRequestId": "pr-1",
  • "files": [
    ],
  • "truncated": false
}

列出仓库树的一个层级

按契约设计不递归:标签页按需导航,而请求大型仓库的整棵树正是本阶段禁止的流量放大器。当该层级超过条目上限时,truncated 会发出提示。

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
ref
string

分支、tag 或 sha。缺省时使用仓库的默认分支。

path
string

要列出的目录。缺省或为空即根目录。

响应

响应示例

Content type
application/json
{
  • "ref": "dev",
  • "path": "apps/api",
  • "entries": [
    ],
  • "truncated": false
}

与 git 提供商开始 OAuth

不重定向:返回 URL,由客户端决定何时让浏览器跳转。state 经 HMAC 签名,正是这一点防止回调被伪造。

Authorizations:
bearer
path Parameters
projectId
required
string
provider
required
string
枚举: "github" "gitlab"

响应

响应示例

创建仓库并运行 Gitflow 引导

同步执行:只有在整个引导过程(永久分支、保护规则、模板)运行完毕后才会返回响应——背后没有 worker 也没有队列。它是幂等且可恢复的,因此失败后再次调用会从失败的步骤继续。通过 GET /projects/:id/git/bootstrap 跟踪进度并读取失败原因。

Authorizations:
bearer
path Parameters
projectId
required
string
provider
required
string
枚举: "local" "github" "gitlab"
Request Body schema: application/json
required
name
required
string

仓库在提供商上的名称。

visibility
required
string
枚举: "public" "private"
namespace
string

组织或群组。省略时,仓库创建在登记凭据者的个人账户下。

响应

请求示例

Content type
application/json
{
  • "name": "checkout",
  • "visibility": "private",
  • "namespace": "acme"
}

响应示例

Content type
application/json
{
  • "repository": {
    },
  • "bootstrap": {
    }
}

接入一个已有仓库,不创建任何东西

用 getRepo 校验访问权限,并生成引导将要执行的计划(dry-run)——缺失的分支、缺失的保护规则、文件。不会在仓库上执行任何操作:之后通过 plan/approve 或 plan/skip 做决定。重新接入同一个仓库会收敛(重新生成计划而不会重复记录)。

Authorizations:
bearer
path Parameters
projectId
required
string
provider
required
string
枚举: "local" "github" "gitlab"
Request Body schema: application/json
required
externalId
required
string

仓库在提供商上的标识符:github 上为 owner/repo,gitlab 上为 namespace/path,本地为裸仓库的绝对路径。不会创建任何东西——仓库必须已经存在,且已登记的凭据必须能够访问它。

响应

请求示例

Content type
application/json
{
  • "externalId": "acme/checkout"
}

响应示例

Content type
application/json
{
  • "repository": {
    },
  • "plan": {
    },
  • "alreadyAdopted": false
}

返回 Gitflow 引导状态

当前处于哪一步、是否失败以及在哪里失败、尝试了多少次。逐步的细节来自专用会话中的 bootstrap.step_* 事件。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "status": "provisioning",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "failedStep": null,
  • "lastError": null,
  • "attempts": 1
}

确认分支保护失败并继续

protect_branches 在免费计划的私有仓库上会失败,向导会事先就此发出警告。没有这个出口,唯一的按钮是“重试”,而它总会因同样的原因失败——provision_failed 又会让仪表盘把项目重定向回置备页面,使其永远无法进入。只有保护步骤的失败可以被确认:它是最后一步,也是唯一一个失败后仍留下可用仓库的步骤。产品自身的合并锁(RN-006)不依赖提供商的保护,会继续生效。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "status": "provisioned"
}

返回引导计划以及对它做出的决定

存在计划且 decision: null 是什么都不会运行的状态——等待批准或按原样接入(RN-045)。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "plan": {
    },
  • "decision": null,
  • "decidedAt": null,
  • "decidedBy": null
}

批准整个计划并运行引导

批准是全有或全无的:批准零散的步骤会破坏 dev←main, qa←dev, rc←qa 级联。实际运行的是在执行时重新推导的计划——等于或小于所展示的,绝不会更大。

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
planGeneratedAt
required
string <date-time>

你所看到的计划的 generatedAt。乐观锁:如果计划自那以后已被重新生成(重新接入,或仓库发生了变化),决定会以 409 拒绝,而不是把针对别的东西给出的同意应用上去。

响应

请求示例

Content type
application/json
{
  • "planGeneratedAt": "2026-08-01T23:45:00.000Z"
}

响应示例

Content type
application/json
{
  • "repository": {
    },
  • "bootstrap": {
    }
}

按原样接入仓库,放弃引导

记录决定,不触碰仓库。计划作为刻意未应用内容的证据保留,引导游标也不会被改动——没有任何步骤运行。

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
planGeneratedAt
required
string <date-time>

你所看到的计划的 generatedAt。乐观锁:如果计划自那以后已被重新生成(重新接入,或仓库发生了变化),决定会以 409 拒绝,而不是把针对别的东西给出的同意应用上去。

响应

请求示例

Content type
application/json
{
  • "planGeneratedAt": "2026-08-01T23:45:00.000Z"
}

响应示例

Content type
application/json
{
  • "repository": {
    },
  • "bootstrap": {
    }
}

返回项目已置备的仓库

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000REPOSITORIO000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "provider": "github",
  • "externalId": "904837261",
  • "defaultBranch": "main",
  • "visibility": "private",
  • "origin": "created",
  • "provisionedBy": "01JC4Z0000USUARIO0000000001",
  • "createdAt": "2026-07-23T10:00:00.000Z",
  • "updatedAt": "2026-07-23T10:00:00.000Z"
}

基础设施

就绪检查——进程确实能够处理流量

执行 select 1。只透露数据库是否响应;不透露拓扑或版本。之所以公开,是因为调用方是 kubelet,它不携带令牌。

响应

响应示例

Content type
application/json
{
  • "service": "api",
  • "status": "ok",
  • "timestamp": "2026-07-27T15:40:00.000Z",
  • "details": { }
}

存活检查——进程仍在处理请求

故意不访问数据库。如果访问,一个缓慢的 Postgres 会让所有副本同时重启,把性能降级变成全面停机。Pod 由 /health 从负载均衡中摘除。

响应

响应示例

Content type
application/json
{
  • "service": "api",
  • "status": "ok",
  • "timestamp": "2026-07-27T15:40:00.000Z",
  • "details": { }
}

以 Prometheus exposition 格式暴露指标

不是 JSON:而是 exposition 格式的 text/plain。出于必要而公开(抓取器不携带令牌),并通过网络加以限制——生产环境的 Ingress 在边缘阻止此路径,NetworkPolicy 只允许监控命名空间访问。

响应

响应示例

Content type
text/plain
# HELP oban_queue_depth Oban queue depth
# TYPE oban_queue_depth gauge
oban_queue_depth{queue="default",state="available"} 0

为所请求的平台下载本地 runner 的独立二进制文件

GitHub Releases 代理——platform 只接受 linux-x64、linux-arm64、darwin-arm64。无需认证:二进制文件不是机密。在返回任何内容之前,字节会与同一 Release 的 checksums.txt 核对(ADR 0149,RN-525);该路由不验证清单的签名——这是完整性而非来源,验证签名的是 install.sh。

响应

内部

创建一个安装的第一个账户,且已验证

供一行命令安装器使用,它运行在未配置邮件传输的环境中:生成的 .env 不含任何邮件变量,MAIL_TRANSPORT 回落为 log,而常规注册会等待一封永远不会到达的邮件。账户一出生即已验证,因为运行安装器的人已经证明了比控制一个邮箱更强的东西——他们控制着这台机器、.env 和 Docker 守护进程。常规注册不受影响。当安装中已有任何用户时以 409 拒绝:条件针对的是安装,而非这个邮箱,因此迁移恢复会通过同一检查让这一步保持静默。密码绝不在此生成,除了 argon2id 哈希外也绝不存储在任何地方;个人 workspace(RN-410)在同一事务中创建。

Authorizations:
service-token
Request Body schema: application/json
required
email
required
string

所有者的邮箱,在 TTY 中输入。在写入任何内容之前进行规范化;安装器会把它记录在标记中,因为邮箱用于识别身份,并不是机密。

senha
required
string

无回显读取,并由安装器确认。用完即弃——绝不写入 .env、标记或日志,也绝不由任何代码生成:不存在账户以脚本选择的密码诞生的路径。最低要求是领域策略,与注册使用的是同一段代码;这里的最大长度是对 argon2id 的保护,而不是策略。

nome
string

显示名称。省略时:个人 workspace 的名称回落为邮箱的本地部分(RN-410)——不会编造任何东西。

响应

请求示例

Content type
application/json
{
  • "email": "voce@exemplo.dev",
  • "senha": "uma frase longa e minha",
  • "nome": "Fulana de Tal"
}

响应示例

Content type
application/json
{
  • "userId": "01JC4Z0000USUARIO0000000001",
  • "email": "voce@exemplo.dev",
  • "workspaceId": "01JC4Z0000WORKSPACE00000001"
}

读取声明式 gate 注册表

注册表只做描述,不做执行:没有任何 gate 会因为它而被强制执行,在此修改字段也不会改变任何行为。每个 gate 都说明其通过的证据存放在哪里(evidencia),因为并非所有证据都在事件日志中。

Authorizations:
service-token

响应

响应示例

Content type
application/json
{
  • "version": 1,
  • "gates": [
    ]
}

发布提示词模板的一个版本,按哈希幂等

如果同一 name 已存在哈希相同的版本,则不会创建新版本——而是返回已有版本(幂等命中不会改变 HTTP 状态:为简单起见始终为 201——响应体与新建时完全相同)。

Authorizations:
service-token
Request Body schema: application/json
required
name
required
string
version
required
string
body
required
string
hash
required
string

响应

请求示例

Content type
application/json
{
  • "name": "dev-agent-kickoff",
  • "version": "3",
  • "body": "You are the dev agent for the {{modulo}} module...",
  • "hash": "sha256:9f2c..."
}

响应示例

Content type
application/json
{
  • "name": "dev-agent-kickoff",
  • "version": "3",
  • "body": "You are the dev agent for the {{modulo}} module...",
  • "hash": "sha256:9f2c...",
  • "active": true
}

按名称查找提示词模板

指定 version 时按相等查找;省略时查找最新的 active 版本。模板(或所请求的版本)不存在时返回 404。

Authorizations:
service-token
path Parameters
name
required
string
query Parameters
version
string
示例: version=3

响应

响应示例

Content type
application/json
{
  • "name": "dev-agent-kickoff",
  • "version": "3",
  • "body": "You are the dev agent for the {{modulo}} module...",
  • "hash": "sha256:9f2c..."
}

为全新安装注册机器设备密钥

供一行命令安装器在创建第一个账户后立即使用:本地代理需要一份凭据,而此前唯一存在的凭据绑定在项目上——而此时安装中还没有任何项目。密钥对在机器上生成,只有公开的一半到达这里;请把返回的 id 作为 kid 写入私有 JWK(RN-475),这是磁盘上的文件与服务器上公开一半之间唯一的关联。请求体中故意没有 userId:所有者是该安装的唯一用户,由 api 解析,因此持有服务令牌绝不意味着可以选择为谁签发凭据。注册即替换:所有者现有的机器密钥在同一事务中被撤销,因此重装的机器可以工作,也不可能存在上千把机器密钥。项目密钥(ADR 0118)不受影响。

Authorizations:
service-token
Request Body schema: application/json
required
name
required
string

供人以后认出这台机器的名称,显示在它所服务的每个项目的设备密钥列表中。不要求唯一。安装器会建议主机名;api 不会从中推导任何东西。

publicKeyJwk
required
string

Ed25519 公钥 JWK(RFC 8037),序列化为 JSON。密钥对在机器上生成,私有的一半从不传输——携带 d 的 JWK 会以 400 拒绝并说明原因,绝不存储。

响应

请求示例

Content type
application/json
{
  • "name": "servidor-de-casa",
  • "publicKeyJwk": "{\"kty\":\"OKP\",\"crv\":\"Ed25519\",\"x\":\"…\"}"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000CHAVE000000000001",
  • "userId": "01JC4Z0000USUARIO0000000001",
  • "name": "servidor-de-casa",
  • "createdAt": "2026-09-12T12:00:00.000Z",
  • "replacedKeyIds": [ ]
}

在所有提供商之间同步模型目录

绝不会因为某一个提供商而失败:每个提供商在报告中各自作答,附带被跳过的原因以及失败时的来源。未响应的提供商会被跳过,而不是被标记为不可用。

Authorizations:
service-token

响应

响应示例

Content type
application/json
{
  • "porProvider": [
    ]
}

以树形展示项目的 backlog,供 PO 阅读已写下的内容

与 Backlog 标签页相同的 epic → story → task 树,经由同一用例(每个项目三次读取,绝无 N+1)。PO 借此看到孤立的 epic 和没有任务的 story,而不是重新创建已有内容(RN-164)。

Authorizations:
service-token
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

项目的业务规则及其覆盖情况,供 PO 阅读

项目所有会话中的每一条 artifact.business_rule——而不仅是当前会话的,那曾是 PO 启动上下文的上限——带有完整的 description 以及哪些 story 已引用每条规则。uncoveredCount 是待办项:没有任何 story 覆盖的规则(RN-164)。完全没有规则的项目返回 200 和空列表:“尚未捕获任何规则”不是错误。

Authorizations:
service-token
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "rules": [
    ],
  • "uncoveredCount": 2
}

在项目的真实容器内执行终端命令(RN-492)

仅由 engine 调用,当 Engine.Actions.TerminalExecutor 判定命令应在真实容器内执行时(execution_mode: container 且有已登记的 running 记录)。代理到 ContainerBrokerPort.exec(ADR 0130/0134)——broker 五个操作中最后一个获得真实调用方的。响应中的 sucesso: false——绝不是抛出的错误——是 broker 拒绝或不可达时的正常形态:在登记的 running 记录与本次调用之间,容器可能已在外部死亡或被移除(RN-486,登记状态与观测状态绝不合并),这是命令失败,而非传输错误。

Authorizations:
service-token
path Parameters
projectId
required
string
Request Body schema: application/json
required
comando
required
string

shell 命令,由 sh -c 在容器内解释——与在容器外运行的终端操作约定相同。

cwd
string

容器内的工作目录。已由 engine 从宿主机路径转换(RN-492)——此 DTO 不会重复该转换。省略时在 /work(项目根目录)运行。broker 会重新校验它位于 /work 内,否则拒绝(DiretorioForaDoEscopoError)。

timeoutMs
number

超时时间,以毫秒计。省略时使用 broker 的默认值。

object

AT-612: run in the task QA instance instead of the work container. Set by the engine from the gate context, never by the model.

响应

请求示例

Content type
application/json
{
  • "comando": "npm test",
  • "cwd": "/work/.worktrees/dev-api",
  • "timeoutMs": 300000,
  • "alvo": {
    }
}

响应示例

Content type
application/json
{
  • "sucesso": true,
  • "exitCode": 0,
  • "output": "ok\n",
  • "timedOut": false,
  • "motivo": "o broker de container não respondeu em http://broker:8090: timeout"
}

broker 自行组装容器规格所需的信息

项目标识、执行模式以及 Architect 当前的镜像决定。broker 在把任何东西交给守护进程之前都会重新校验——从这里读取并不等于信任它,拒绝时会指明字段。不返回任何绝对路径:绑定源由守护进程依据宿主机文件系统解析,而来自 api 容器内部的路径会静默挂载一个空文件夹。传递的是 localizacao(RN-503)——使用 broker 两个根目录中的哪一个,以及该根目录未覆盖的相对段。

Authorizations:
service-token
path Parameters
projectId
required
string
query Parameters
papel
string
值: "qa"
task
string

响应

响应示例

Content type
application/json
{
  • "projectId": "f52be111-0000-4000-8000-000000000000",
  • "projectSlug": "exp002",
  • "workspaceId": "aaaaaaaa-0000-4000-8000-000000000000",
  • "workspaceDirName": "exp002-f52be111",
  • "executionMode": "container",
  • "localizacao": {
    },
  • "usuarioDaPasta": {
    },
  • "imagem": {
    },
  • "imagemVersao": 3,
  • "comandoDoApp": "string",
  • "ports": [
    ],
  • "dns": [
    ],
  • "extraHosts": [
    ],
  • "qa": {
    }
}

项目的工作远程仓库,用于 fetch 和 push

返回干净的源地址(不嵌入凭据),对于远程提供商,还返回即时解密的 workspace 所有者令牌(RN-058)。使用方按每次调用注入令牌,绝不写入文件——.git/config 位于 RN-075 授予 dev agent 自动批准读取权限的文件夹内。

Authorizations:
service-token
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{}

本地代理报告一轮镜像的结果(RN-517)

仅由 engine 调用,在 runner 通过通道推送 mirror_sync_result 之后——与 workspace_confirm 走同一路径(runner → 通道 → engine → api),绝无第二套机制:engine 负责报告,不写表。这是遥测,不是领域事件:绝不写入 session_events(一轮镜像没有会话,而 session_id 是 NOT NULL,与把 rag_searches 做成表的理由相同),也绝不是 proposed_action(镜像写入是用户声明的配置,不是代理请求执行操作)。决定结果的是 ok——绝不是计数或消息是否存在:复制了 0 个文件的一轮是正常的,绝不能与从未运行的一轮无法区分。记录绝不会破坏它所测量的东西:调用此接口时复制已经完成,engine 只会在此记录拒绝。目标在此期间被清除的项目仍然会记录——这一轮确实发生了,而它的错误通常正是解释问题所在的线索。

Authorizations:
service-token
path Parameters
projectId
required
string
Request Body schema: application/json
required
ok
required
boolean

复制的真实结果,由本地代理在完成后报告——绝不是在这一轮结束前乐观地报“ok”。

destination
string

这一轮实际解析到的目标(成功时)或尝试使用的目标(失败时),位于用户的机器上。在记录中冻结:把项目当前的目标显示在昨天的复制旁边,等于界面在对一个那轮从未触及的文件夹做出断言。当失败与目标本身有关时省略。

filesCopied
number

这一轮复制的普通文件数。0 是一个数字,而不是缺失——“已同步但什么也没复制”是一种独立的状态(RN-088)。

filesSkipped
number

git 列出的、不是普通文件的条目——嵌套仓库(dev agent 的 worktree 就是一个)、符号链接,或在列出和复制之间消失的文件。

filesRefused
number

被逐文件防护拒绝的目标(逃出目标目录的符号链接)。会被计数,绝不吞掉。

error
string

具名的失败消息。很长时会截断存储,并说明已截断。它绝不会抹去最近一次成功的同步——哪条是当前的,由比较两个时间戳决定。

响应

请求示例

Content type
application/json
{
  • "ok": true,
  • "destination": "/home/you/mirrors/store",
  • "filesCopied": 412,
  • "filesSkipped": 3,
  • "filesRefused": 0,
  • "error": "o espelho não conseguiu listar o trabalho com o git: not a git repository"
}

响应示例

Content type
application/json
{
  • "recorded": true,
  • "status": "synced"
}

模块之间的契约,供 dev agent 阅读(RN-684)

当前 module_map 中每个模块一条记录:它消费什么(dependeDe,即映射中的 dependsOn)以及它暴露什么(expoe,来自 Architect 当前的 artifact.module_contracts,未声明时为 null)。dev agent 读取它,而不是打开另一个模块的 worktree(ADR 0200)。没有契约的项目返回 200 和 status: sem_contratos。

Authorizations:
service-token
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "status": "sem_contratos",
  • "version": 2,
  • "modulos": [
    ],
  • "contratosForaDoMapa": [ ]
}

项目的交付漏斗和部分 DORA 指标,供 PO 阅读

与 analise:funil 脚本(ADR 0089)相同的报告——会话 → 提交 → PR → 合并的漏斗、真实交付周期和真实部署频率——经由相同的纯函数和相同的查询(apps/api/src/application/services/funil-metrics.ts),因此两者对同一事实绝不会出现分歧。补上 docs/fluxo.yml(角色 po,输入 metricas-de-produto,此前为 status: lacuna)(RN-407)。

Authorizations:
service-token
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "project": {
    },
  • "totalActionsConsidered": 18,
  • "funnel": {
    },
  • "leadTimes": {
    },
  • "deploymentFrequency": [
    ]
}

Removes the QA instance of a task (RN-936)

Automatic, no proposal: it only reaches what carries the QA label (the broker guarantees it). Idempotent.

Authorizations:
service-token
path Parameters
projectId
required
string
taskId
required
string

响应

响应示例

Content type
application/json
{
  • "sucesso": true,
  • "status": "provisioning",
  • "chave": "a1b2c3d4",
  • "motivo": "string"
}

Brings up the ephemeral QA instance of a task (RN-935)

Records the row, then asks the broker. sucesso: false is the NORMAL shape of a refused broker. At most ONE active instance per project: another task active -> 409 instancia_de_qa_ocupada. runner projects -> 409 qa_nao_suporta_runner.

Authorizations:
service-token
path Parameters
projectId
required
string
taskId
required
string

响应

响应示例

Content type
application/json
{
  • "sucesso": true,
  • "status": "provisioning",
  • "chave": "a1b2c3d4",
  • "motivo": "string"
}

runner 确认 “runner” 项目的路径(RN-423)

仅由 engine 调用,在 runner 连接并通过通道发送 workspace_confirm 之后。runner 是路径的事实来源——api 在对其进行词法重新校验后(即使来自 runner,系统根目录/与 Brabo 重叠仍被禁止),用它报告的值覆盖 workspacePath。幂等:以相同路径重新连接不会再次写入。

Authorizations:
service-token
path Parameters
projectId
required
string
Request Body schema: application/json
required
path
required
string

runner 在宿主机上确认的绝对路径——事实来源(RN-423)。写入之前在此进行词法重新校验;无效时返回 400,绝不写入。

sessionId
string <uuid>

项目最近的会话(ProjectSession.latest_id/1),在 engine 端解析。项目还没有任何会话时为 null/省略——项目仍会被更新,只是跳过审计事件(已接受的缺口,RN-423)。

actorId
string <uuid>

请求 runner 票据的人(确认路径的套接字的所有者)——成为 project.workspace_verified 事件的参与者。省略时:该事件(如果有会话)诞生时没有可识别的参与者。

响应

请求示例

Content type
application/json
{
  • "path": "/home/you/projects/store",
  • "sessionId": "01JC4Z0000SESSAO00000000001",
  • "actorId": "01JC4Z0000USUARIO0000000001"
}

响应示例

Content type
application/json
{
  • "verified": true,
  • "workspacePath": "/home/you/projects/store",
  • "changed": true
}

Removes QA instances whose gate is no longer in flight (RN-937)

The engine sends the task ids it still has in flight; every other active or failed instance is removed. Shared services and the QA network have no broker operation yet (declared gap).

Authorizations:
service-token
Request Body schema: application/json
required
taskIdsEmVoo
required
数组:strings

Task ids that still have a gate in flight; every other active instance is removed.

projectId
string <uuid>

Limit the sweep to one project.

响应

请求示例

Content type
application/json
{
  • "taskIdsEmVoo": [
    ],
  • "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8"
}

响应示例

Content type
application/json
{
  • "removidas": [
    ],
  • "falhas": [
    ]
}

代理对一个检索到的分块的投票(RN-480)

与人工路由相同的用例——没有第二条判定路径。未知的 searchId/chunkId 返回 400,engine 会将其转为错误的工具结果供模型纠正(RN-061),绝不会崩溃。

Authorizations:
service-token
Request Body schema: application/json
required
projectId
required
string <uuid>
searchId
required
string <uuid>
chunkId
required
string <uuid>
verdict
required
string
枚举: "util" "irrelevante"
agent
required
string

代理 slug——投票者。

响应

请求示例

Content type
application/json
{
  • "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8",
  • "searchId": "9b1a67f9-9477-48e5-8a6c-11b70245e1d9",
  • "chunkId": "90e1f3df-a8a1-438e-8dd5-10e45398d051",
  • "verdict": "util",
  • "agent": "qa"
}

响应示例

Content type
application/json
{
  • "searchId": "9b1a67f9-9477-48e5-8a6c-11b70245e1d9",
  • "chunkId": "90e1f3df-a8a1-438e-8dd5-10e45398d051",
  • "verdict": "util",
  • "rank": 0
}

在项目的 RAG 索引上进行混合搜索,供 engine 的工具使用

与 POST /projects/:projectId/rag/search(人工路由)相同的引擎,投射成 engine 的 rag_search 工具所期望的格式。

Authorizations:
service-token
Request Body schema: application/json
required
projectId
required
string <uuid>
query
required
string
topK
number
sessionId
string <uuid>

代理正在运行的会话。缺省表示调用方没有会话——遥测记录仍会写入(RN-479),只是跳过 rag.search 时间线叙述。api 绝不编造:没收到的会话就是不存在的会话。

agent
string

代理 slug,记录为遥测参与者(actor_kind: agent)。缺省时回落为 system 参与者,而不是编造一个用户。

响应

请求示例

Content type
application/json
{
  • "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8",
  • "query": "how the parallelism cap is decided",
  • "topK": 5,
  • "sessionId": "f6567dd8-e069-418e-8893-7d22fcf12459",
  • "agent": "dev-lead"
}

响应示例

Content type
application/json
{
  • "searchId": "9b1a67f9-9477-48e5-8a6c-11b70245e1d9",
  • "hits": [
    ],
  • "degraded": true
}

代表代理提议一个具有外部效果的操作

代理接触 git、终端或花费的唯一入口。permissions.json 在创建时做出决定,deny 优先于授予代理的任何自主权。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
actionType
required
string
枚举: "terminal" "git_commit" "git_push" "pr_open" "spend" "git_repo_create" "git_branch_create" "git_branch_protect" "write_file" "open_adr_pr" "git_merge" "open_infra_pr" "instruction_patch" "parallelize" "raise_max_parallel" "propose_execution_plan" "assess_implementability" "container_start" "container_stop" "container_remove" "container_recreate" "container_start_via_runner" "qa_environment_start"
required
object

在此路由上始终是代理。

required
object

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "actionType": "terminal",
  • "actor": {
    },
  • "payload": {
    }
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRC",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 7,
  • "actionType": "terminal",
  • "payload": {
    },
  • "status": "pending",
  • "resolvedPolicy": "require_approval",
  • "actor": {
    },
  • "decidedBy": null,
  • "decidedAt": null,
  • "rejectionReason": null,
  • "executionResult": null,
  • "createdAt": "2026-07-27T14:33:10.900Z",
  • "updatedAt": "2026-07-27T14:33:10.900Z"
}

为一轮 Anamnesis 组装上下文

一次调用拿到全部,与 Psychologist 的上下文对应。成员列表已排除选择不被画像的人,而窗口内用户的决定通过这里传递,因为它们不在事件日志中。engine 直接从 Postgres 读取事件本身——通过 HTTP 传输会更昂贵,却不会更正确。

Authorizations:
service-token
query Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "competencyCatalog": [
    ],
  • "members": [
    ],
  • "queuedHypotheses": [
    ],
  • "currentProfiles": [
    ],
  • "instructions": [
    ],
  • "decisions": [
    ],
  • "windowFrom": "2026-07-27T12:00:00.000Z"
}

关闭一轮未产出任何画像的 Anamnese 窗口

记录一次零画像的 anamnese 运行,使下一轮从 windowTo 开始——没有它,窗口永远不会前进,每次 tick 都要为同一批材料付费运行新一轮。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
windowFrom
required
string <date-time>
windowTo
required
string <date-time>
eventCount
required
number

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "windowFrom": "2026-07-27T12:00:00.000Z",
  • "windowTo": "2026-07-27T12:15:00.000Z",
  • "eventCount": 12
}

响应示例

Content type
application/json
{
  • "runId": "01JC4Z0000RODADA00000000001",
  • "profiles": [
    ]
}

生成 C4 图(Context + Container)的新版本

制品就是 artifact.c4_diagram 事件:不可变、带版本、有作者,与 artifact.module_map 并列。需要当前的 module_map——没有它就没有可绘制的 Container 层级(400)。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
systemName
required
string

系统/项目名称,用作图的标签。

systemDescription
string
数组:objects (C4AtorInternalDto)

Context 层级的外部参与者(Simon Brown)。Container 层级的容器不放在这里:它们来自项目当前的 module_map。

响应

请求示例

Content type
application/json
{
  • "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8",
  • "systemName": "Brabo",
  • "systemDescription": "Agent-orchestrated engineering platform.",
  • "actors": [
    ]
}

响应示例

Content type
application/json
{
  • "diagrama": {
    },
  • "version": 1
}

记录一次区域委派的结果

completed(附裁决)、failed(附来源)或 dispensed(附理由)——lead 绝不会以半途的结果调用此路由:每次委派在这里诞生时就已经有了结论。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
area
required
string

进行委派的区域——“qa”(Phase 8b)或 “infra”(Phase 8c)。是文本,不是枚举。

taskId
string <uuid>

委派背后的 backlog 任务(如存在)。QA(Phase 8b)总会发送它;Infra(Phase 8c)从不发送——委派针对的是会话,而不是任务。

leadAgent
required
string
subagent
required
string
status
required
string
枚举: "completed" "failed" "dispensed"
parecerArtifactId
string

此子专业裁决对应的 artifact.qa_verdict session_event 的 id——当 status 为 “completed” 时必需。

failureOrigin
string
枚举: "infra" "modelo" "codigo" "politica"

失败的来源(ADR 0020/0038),绝不通过排除法——当 status 为 “failed” 时必需。

failureReason
string
justification
string

lead 为何选择不委派——当 status 为 “dispensed” 时必需。绝不留空:放弃委派是一项被记录的决定,而不是沉默(CLAUDE.md,Phase 8b 第 2 项)。

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "area": "qa",
  • "taskId": "01JC4Z0000TASK00000000001",
  • "leadAgent": "qa-lead",
  • "subagent": "qa-automacao",
  • "status": "completed",
  • "parecerArtifactId": "evt_01jc4z0000parecer000000001",
  • "failureOrigin": "infra",
  • "failureReason": "iteration limit reached without emit_perf_seguranca_verdict",
  • "justification": "story with no relevant performance NFR"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000DELEGACAO00000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z0000SESSAO000000000001",
  • "taskId": "01JC4Z0000TAREFA00000000001",
  • "area": "qa",
  • "leadAgent": "qa-lead",
  • "subagent": "qa-automacao",
  • "status": "completed",
  • "parecerArtifactId": "evt_01jc4z0000parecer000000001",
  • "failureOrigin": null,
  • "failureReason": null,
  • "justification": null,
  • "createdAt": "2026-07-30T12:00:00.000Z"
}

为 dev agent 组装任务的完整上下文

一次调用即可拿到提示词所需的一切:完整的 story、已解析的业务规则以及适用的 ADR。module 将 ADR 限定为该 dev 的模块;未声明模块的 ADR 是横切的,始终包含在内。省略 module 会返回整个集合,这正是 QA 和 SecOps gate 复用同一上下文时所需要的。

Authorizations:
service-token
query Parameters
projectId
required
string
taskId
required
string
module
string
示例: module=api

响应

响应示例

Content type
application/json
{
  • "task": {
    },
  • "story": {
    },
  • "businessRules": [
    ],
  • "adrs": [
    ],
  • "siblingTasks": [
    ],
  • "moduleOpenTasks": [
    ],
  • "moduleOpenTasksTotal": 0,
  • "moduleContract": {
    },
  • "primeiraDoModulo": true,
  • "decisoes": [
    ],
  • "decisoesDoProjeto": [
    ]
}

创建一个 backlog epic

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
title
required
string
description
string

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "title": "Shopping cart",
  • "description": "Everything the buyer does before paying."
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000EPICO000000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "title": "Shopping cart",
  • "description": "Everything the buyer does before paying.",
  • "createdAt": "2026-07-25T08:30:00.000Z",
  • "updatedAt": "2026-07-25T08:30:00.000Z"
}

为 engine 分页读取会话的事件日志

用于重新水合对话式代理的历史,并读取其启动所需的制品。对应的人工路由受 RBAC 保护;这一个受服务令牌保护。latest=true 返回尾部(仍按 seq 升序)并忽略 afterSeq;types 将该页限定为这些事件类型。无论哪种情况,每页上限都是 200(ADR 0060)。

Authorizations:
service-token
path Parameters
sessionId
required
string
query Parameters
projectId
required
string
afterSeq
string
示例: afterSeq=40
limit
string
示例: limit=200
latest
string
示例: latest=true

获取日志尾部;忽略 afterSeq。

types
string
示例: types=artifact.product_brief,artifact.business_rule

以逗号分隔的事件类型(最多 20 个)。只有这些类型的事件计入 limit。

响应

响应示例

Content type
application/json
{
  • "items": [
    ],
  • "nextCursor": 41
}

代表代理向会话日志追加一个事件

与人工路由相同的用例和相同的原子 seq 分配。Psychologist 的假设不经过这里:它们有自己的路由,附带证据校验。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
type
required
string

见 docs/reference/events.md。

actorKind
required
string
枚举: "user" "agent" "system"
actorId
required
string

发出它的代理的 slug。

required
object

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "type": "agent.tool_call",
  • "actorKind": "agent",
  • "actorId": "dev-api",
  • "payload": {
    }
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRB",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 41,
  • "type": "chat.message",
  • "actor": {
    },
  • "payload": {
    },
  • "createdAt": "2026-07-27T14:30:58.512Z"
}

记录 QA 或 SecOps 对任务 PR 的裁决

响应中的 nextAction 是 engine 所遵从的:correct 退回给 dev,run_secops 推进 gate,done 将其交给用户,await_user 暂停周期直到未决问题得到回答(RN-860,不计入修正次数),blocked 表示修正上限已用尽。合并绝不自动进行——done 只表示轮到人来操作了。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
taskId
required
string <uuid>
gate
required
string
枚举: "qa" "secops"
veredito
required
string
枚举: "approved" "changes_requested" "needs_user_decision"

needs_user_decision(仅 QA,RN-860):周期等待用户对一个未决问题的回答——不计为一次修正。

resumo
required
string
itens
required
数组:strings

需要修改什么,逐项列出。

pergunta
string

配合 needs_user_decision:新的未决问题(最多 500 个字符)。

sugestao
string

配合 needs_user_decision:代理的建议。

openQuestionId
string <uuid>

配合 needs_user_decision:一个已存在的未决问题,而不是新问题。

maxCorrections
number

任务变为 blocked 之前往返次数的上限。省略时使用领域默认值。

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "taskId": "01JC4Z0000TAREFA00000000001",
  • "gate": "qa",
  • "veredito": "changes_requested",
  • "resumo": "Missing tests for the insufficient-stock path.",
  • "itens": [
    ],
  • "pergunta": "Should a nonexistent code answer 404?",
  • "sugestao": "404 with a plain message.",
  • "openQuestionId": "4c8aa973-c398-4859-8f2e-3fe00dc96a12",
  • "maxCorrections": 3
}

响应示例

Content type
application/json
{
  • "nextAction": "run_secops",
  • "task": {
    },
  • "openQuestionId": "4c8aa973-c398-4859-8f2e-3fe00dc96a12"
}

从一个代理向另一个代理提议 handoff

以 offered 状态诞生。接受者是一个人,通过人工路由——代理不会激活代理。有两个例外。携带 product_brief、由一次“我准备好了——需求已验证”点击所请求的 Creative→PO 提议,会代表点击者被接受,以该人为参与者并在载荷中带有 implicito(RN-658,ADR 0185)。当 backlog 已被覆盖(至少一条业务规则,且没有一条缺少 story)、仓库为 local 且项目中没有 git 凭据时,PO 到 Arquiteto 的 handoff 由系统接受(RN-660,ADR 0186);aceiteAutomatico 说明是否发生,以及未发生的原因。无论哪种情况,响应随后都会带有 status: accepted。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
fromAgent
required
string
toAgent
required
string
artifactId
string

引发该 handoff 的制品对应的 session_event 的 ULID。

seAusente
boolean

仅当还没有人拿到时(ADR 0182,RN-636):如果项目的任何会话中已有给该目标的待处理提议,则返回它(desfecho: ja_oferecido)而不是替换它。AppSec 会发送这个字段。

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "fromAgent": "criativo",
  • "toAgent": "po",
  • "artifactId": "01JC4Z8QK3M7YV2N5T9B0PXHRB",
  • "seAusente": true
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000HANDOFF00000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "fromAgent": "criativo",
  • "toAgent": "po",
  • "artifactId": "01JC4Z0000ARTEFATO000000001",
  • "status": "offered",
  • "createdAt": "2026-07-24T10:00:00.000Z",
  • "updatedAt": "2026-07-24T10:05:00.000Z",
  • "desfecho": "criado",
  • "aceiteAutomatico": {
    }
}

记录一轮分析及其假设

每条假设都需要引用本会话中确实存在的事件——编造的证据会以 400 被拒绝,这正是假设与意见的区别。本会话的上一轮将被取代。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
tier
required
string
枚举: "leve" "pesada"

两个层级使用的确实是不同的模型;成本也不同。

triggeredBy
required
string
枚举: "auto" "manual"
eventCount
required
number

被分析日志的大小。

cause
string
枚举: "normal" "timeout" "kill" "crash" "node_shutdown" "unknown"

由 engine 分类的原因。决定是否需要 terminationAnalysis 的是它,而不是终止状态。设为可选,以免在滚动部署期间破坏旧版 engine。

required
数组:objects (HypothesisDraftDto)

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "tier": "leve",
  • "triggeredBy": "auto",
  • "eventCount": 128,
  • "cause": "timeout",
  • "hypotheses": [
    ]
}

响应示例

Content type
application/json
{
  • "analysisId": "01JC4Z0000ANALISE0000000001",
  • "hypotheses": [
    ]
}

返回基础设施 PR 的文件,供 gate 读取

内容来自 proposed_action 自身的载荷:基础设施制品从不接触 worktree,与 ADR 相同。

Authorizations:
service-token
path Parameters
prActionId
required
string
query Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "title": "api's production Dockerfile",
  • "files": [
    ]
}

组装 InfraAgent 的初始上下文

当前的 module_map 加上相关的基础设施 ADR,再加上 Architect 的模块路由(ADR 0131)——Infra Lead 在提议 container_start 时从中选择的候选项。

Authorizations:
service-token
query Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "moduleMap": {
    },
  • "adrs": [
    ],
  • "gitProvider": "github",
  • "moduleRouting": {
    },
  • "projectImage": {
    }
}

记录 QA 或 SecOps 对基础设施 PR 的裁决

与 dev PR 相同的流水线和相同的状态机。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
prActionId
required
string <uuid>

打开该 PR 的 open_infra_pr proposed_action。

gate
required
string
枚举: "qa" "secops"
veredito
required
string
枚举: "approved" "changes_requested"
resumo
required
string
itens
required
数组:strings
maxCorrections
number

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "prActionId": "01JC4Z8QK3M7YV2N5T9B0PXHRD",
  • "gate": "secops",
  • "veredito": "approved",
  • "resumo": "Non-root image with no secret in ARG.",
  • "itens": [ ],
  • "maxCorrections": 3
}

响应示例

Content type
application/json
{
  • "nextAction": "done",
  • "artifact": {
    }
}

为代理的指令文件提议一个补丁

会变成 proposed_action,而不是直接写入:改变代理的行为是一种外部效果,要经过与其他一切相同的审批流水线。这闭合了假设 → 补丁的循环。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
agent
required
string
proposedContent
required
string

文件最终的完整内容,而不是 diff。

rationale
required
string
hypothesisId
string <uuid>

引发该补丁的假设。正是它闭合了 Anamnesis 循环。

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "agent": "dev-api",
  • "proposedContent": "# dev-api\n\nAlways run the suite before opening the PR.",
  • "rationale": "The task was reopened three times for lack of a criterion.",
  • "hypothesisId": "01JC4Z0000HIPOTESE000000001"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRC",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 7,
  • "actionType": "terminal",
  • "payload": {
    },
  • "status": "pending",
  • "resolvedPolicy": "require_approval",
  • "actor": {
    },
  • "decidedBy": null,
  • "decidedAt": null,
  • "rejectionReason": null,
  • "executionResult": null,
  • "createdAt": "2026-07-27T14:33:10.900Z",
  • "updatedAt": "2026-07-27T14:33:10.900Z"
}

运行一个经过计量的 LLM 回合,支持工具

计量是强制的:每个回合都记录 token_usage,正是这一点让预算有意义。不记录任何事件——由 engine 叙述事件日志。提供商失败时在 error 中以 200 返回,因为 usage 中的计费仍然有效:即使失败,该回合也产生了花费。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
agentId
string

在团队面板中把成本归到此代理名下。

required
数组:objects

已由 engine 的 ContextManager 组装好的历史。

数组:objects

提供给模型的工具;parameters 是 JSON Schema。

catalogoCompleto
boolean

请求完整的工具目录:此次调用跳过 Jev 工具路由器(ADR 0179)。当某一步受限的菜单导致模型没有调用工具就作答、engine 重复这一步时会设置它。

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "agentId": "dev-api",
  • "messages": [
    ],
  • "tools": [
    ],
  • "catalogoCompleto": true
}

响应示例

Content type
application/json
{
  • "message": {
    },
  • "usage": {
    },
  • "error": null,
  • "errorCode": null,
  • "modelName": "llama3.2:3b",
  • "truncated": true,
  • "toolRouting": {
    }
}

运行一个以流式返回响应的 LLM 回合

与 llm-turn 语义相同,逐帧交付。done 帧携带 usage——没有它,该回合将没有计费记录。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
agentId
string
required
数组:objects
数组:objects
catalogoCompleto
boolean

请求完整的工具目录:此次调用跳过 Jev 工具路由器(ADR 0179)。当某一步受限的菜单导致模型没有调用工具就作答、engine 重复这一步时会设置它。

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "agentId": "criativo",
  • "messages": [
    ],
  • "tools": [
    ],
  • "catalogoCompleto": true
}

提议提高某个区域的并行度上限

拒绝提议等于或低于当前值的上限:Anamnesis 周期性运行,否则每一轮都会重新提议同样的内容,用噪声填满用户需要阅读的队列。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
area
required
string

上限将要提高的区域。

proposto
required
number >= 1

提议的上限。必须高于当前值——提议相同或更低的值会成为用户需要阅读的队列中的噪声,而 Anamnesis 是周期性运行的。

rationale
required
string

以观察到的决定为依据,而不是印象。

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "area": "dev",
  • "proposto": 4,
  • "rationale": "You authorized the same request four times in this window, and none was denied."
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRC",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 7,
  • "actionType": "terminal",
  • "payload": {
    },
  • "status": "pending",
  • "resolvedPolicy": "require_approval",
  • "actor": {
    },
  • "decidedBy": null,
  • "decidedAt": null,
  • "rejectionReason": null,
  • "executionResult": null,
  • "createdAt": "2026-07-27T14:33:10.900Z",
  • "updatedAt": "2026-07-27T14:33:10.900Z"
}

声明模块之间契约的新版本

制品就是 artifact.module_contracts 事件:不可变、带版本、有作者,与 artifact.module_map 并列。每次调用携带完整列表并替换上一版本。模块消费什么不在这里写:那是当前 module_map 的 dependsOn。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
required
数组:objects (ContratoDeModuloInternalDto)

完整的契约列表:每次调用都是一个新版本,替换上一个版本。模块消费的内容不在这里——它在读取时由当前 module_map 的 dependsOn 推导而来。

响应

请求示例

Content type
application/json
{
  • "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8",
  • "contratos": [
    ]
}

响应示例

Content type
application/json
{
  • "contratos": [
    ],
  • "version": 1
}

发布 module_map 的新版本

历史不可变:每次发布都是新增一个版本,当前版本是 version 最高的那个。模块之间存在依赖环时映射会以 400 被拒绝——图必须是无环的。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
required
数组:objects

模块图。存在环会使映射以 400 被拒绝——校验在领域层。每个模块可以声明 resources(cpus、memoryMb、pidsLimit——三项全有或全无);部分声明、超过容器上限的值,或模块总和超过上限,同样返回 400(RN-683)。

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "modules": [
    ]
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000MODULEMAP00000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "modules": [
    ],
  • "version": 3,
  • "createdAt": "2026-07-24T16:00:00.000Z"
}

将当前 module_map 的每个模块路由到一个候选镜像

制品就是 artifact.module_routing 事件:不可变、带版本、有作者,与 artifact.module_map/artifact.project_image/artifact.c4_diagram 并列。每个条目都按与 choose_project_image 相同的规则校验(显式 tag/digest,拒绝 latest,rationale 不能过于简单);模块名不在当前 module_map 中、列表为空或模块重复,都会以 400 被拒绝。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
required
数组:objects (RoteamentoDeModuloInternalDto)

当前 module_map 的每个模块一项。候选镜像是 Architect 的提议,而不是决定——Infra 在之后的步骤中从候选项中选择。

响应

请求示例

Content type
application/json
{
  • "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8",
  • "roteamento": [
    ]
}

响应示例

Content type
application/json
{
  • "roteamento": [
    ],
  • "version": 1
}

会话是否有阻止其关闭的待办工作?

在心跳超时时由 engine 的 SessionServer 查询。pending: true 会让超时被重新调度而不是关闭会话,motivo 会写入 engine 的日志——一个不说明原因就不关闭的会话是无法诊断的。

Authorizations:
service-token
path Parameters
sessionId
required
string

响应

响应示例

Content type
application/json
{
  • "pending": true,
  • "motivo": "handoff po → arquiteto aguardando aceite",
  • "aguardandoUsuarioDesde": "2026-09-18T12:00:00.000Z"
}

记录本轮推导出的熟练度画像

目录之外的能力会被拒绝,引用其他项目事件的证据也会被拒绝——两种校验都存在,因为模型在这两点上都会出错。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
windowFrom
required
string <date-time>
windowTo
required
string <date-time>
eventCount
required
number
required
数组:objects (ProficiencyDraftDto)

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "windowFrom": "2026-07-27T12:00:00.000Z",
  • "windowTo": "2026-07-27T12:15:00.000Z",
  • "eventCount": 240,
  • "profiles": [
    ]
}

响应示例

Content type
application/json
{
  • "runId": "01JC4Z0000RODADA00000000001",
  • "profiles": [
    ]
}

设置项目的容器镜像

制品就是 artifact.project_image 事件:不可变、带版本、有作者。修订意味着发出新版本,绝不覆盖。在尚未有版本之前,项目的容器不会启动,Code 标签页返回 409。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
image
required
string

带有显式 TAG 或 digest 的 OCI 引用。latest 会以 400 拒绝——该规则位于领域层。

rationale
required
string

为什么选这个镜像。至少 10 个字符。

network
string
默认值: "none"
枚举: "none" "egress"

容器的网络姿态。none 是默认值,正是它让“在里面,代理是自由的”成为一句安全的话。

object

资源上限。超过最大值时,决定会被拒绝,绝不会被悄悄降级。

响应

请求示例

Content type
application/json
{
  • "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8",
  • "image": "node:22-bookworm-slim",
  • "rationale": "The module_map is TypeScript on Node 22; the slim variant has the runtime and nothing else.",
  • "network": "none",
  • "resources": {
    }
}

响应示例

Content type
application/json
{
  • "decisao": {
    },
  • "version": 1,
  • "containerDePe": {
    }
}

为一轮 Psychologist 组装上下文

alreadyAnalyzed 为自动路径提供幂等性:为 true 时 worker 直接短路,不花费任何 token。之前的假设也会一并带上,以免本轮重复。

Authorizations:
service-token
path Parameters
sessionId
required
string
query Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "alreadyAnalyzed": false,
  • "sessionStatus": "closed_abnormally",
  • "terminationReason": "heartbeat_timeout",
  • "businessRules": [
    ],
  • "priorHypotheses": [
    ]
}

当刚写下的业务规则与已有规则相似时发出警告

用 RAG 嵌入模型对标题和项目规则的标题(最近 100 条)进行嵌入,余弦相似度 ≥ 阈值时发出警告。从不拒绝。没有嵌入提供商时检查会被跳过并说明原因,同样会在事件日志中叙述。嵌入花费作为单独的 token_usage 记录计量(参与者 system/duplicata-semantica)。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
kind
required
string
值: "business_rule"
title
required
string

刚刚追加的规则的标题。规范化后标题相同的规则(RN-080 让新的生效)不参与比较。

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "kind": "business_rule",
  • "title": "Greeting with the caller name"
}

响应示例

Content type
application/json
{
  • "status": "warned",
  • "similarTo": {
    },
  • "closest": {
    },
  • "similarity": 0.83,
  • "threshold": 0.8,
  • "compared": 12,
  • "total": 12,
  • "reason": "provider \"ollama\" did not answer",
  • "message": "string"
}

创建一个带功能/非功能需求、DoD、DoR 和所覆盖规则的 story

businessRuleIds 为规则→story 覆盖提供数据。每个 id 必须引用一个确实存在的 artifact.business_rule 事件——校验会拒绝编造的 id。响应还携带 semanticDuplicate(RN-681):一个基于嵌入、与项目 story 对比的警告,绝不是拒绝。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
epicId
required
string <uuid>
title
required
string
description
string
rf
数组:strings
rnf
数组:strings
dod
数组:strings
dor
数组:strings
businessRuleIds
数组:strings

每个 id 都必须引用一个确实存在的 artifact.business_rule 事件——编造的 id 会被拒绝。

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "epicId": "01JC4Z0000EPICO000000000001",
  • "title": "Add item to cart",
  • "description": "As a buyer, I want to gather items before paying.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "businessRuleIds": [
    ]
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000HISTORIA000000001",
  • "epicId": "01JC4Z0000EPICO000000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "title": "Add item to cart",
  • "description": "As a buyer, I want to gather items before paying.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "businessRuleIds": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "moduleIds": [
    ],
  • "status": "ready",
  • "proposedReady": true,
  • "returnedReason": "DoD too generic — spell out the acceptance criteria.",
  • "returnedAt": "2026-08-02T14:00:00.000Z",
  • "archivedAt": null,
  • "archivedReason": null,
  • "createdAt": "2026-07-25T09:00:00.000Z",
  • "updatedAt": "2026-07-25T09:40:00.000Z",
  • "semanticDuplicate": {
    }
}

归档一个草稿 story

该 story 及其任务离开 backlog、覆盖、计划和认领;记录保留,backlog.story_archived 记录此事,以 PO 为参与者(RN-727)。

Authorizations:
service-token
path Parameters
storyId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
reason
string

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "reason": "Duplicate of \"Register a user\"."
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000HISTORIA000000001",
  • "epicId": "01JC4Z0000EPICO000000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "title": "Add item to cart",
  • "description": "As a buyer, I want to gather items before paying.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "businessRuleIds": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "moduleIds": [
    ],
  • "status": "ready",
  • "proposedReady": true,
  • "returnedReason": "DoD too generic — spell out the acceptance criteria.",
  • "returnedAt": "2026-08-02T14:00:00.000Z",
  • "archivedAt": null,
  • "archivedReason": null,
  • "createdAt": "2026-07-25T09:00:00.000Z",
  • "updatedAt": "2026-07-25T09:40:00.000Z"
}

补全一个已有的草稿 story,而不是重新创建

businessRuleIds 会追加到已关联的规则中;非空列表替换当前列表,省略的列表保持不变。写入后,story 按与创建 story 相同的标准提升(ready 用于 auto 模式,proposedReady 用于 manual 模式)(RN-720)。

Authorizations:
service-token
path Parameters
sessionId
required
string
storyId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
description
string
rf
数组:strings
rnf
数组:strings
dod
数组:strings
dor
数组:strings
businessRuleIds
数组:strings

追加到 story 已引用的规则中(补全绝不会解除规则的关联);每个新 id 都必须引用一个已存在的 artifact.business_rule。

questionId
string <uuid>

RN-859(ADR 0214):一个用户已经回答过的未决问题——只有这样,ready story(没有执行中的任务)才能被修正。

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "description": "As a buyer, I want to pay by card.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "businessRuleIds": [
    ],
  • "questionId": "ffa0420e-f70b-4e5b-99a0-434bff860467"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000HISTORIA000000001",
  • "epicId": "01JC4Z0000EPICO000000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "title": "Add item to cart",
  • "description": "As a buyer, I want to gather items before paying.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "businessRuleIds": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "moduleIds": [
    ],
  • "status": "ready",
  • "proposedReady": true,
  • "returnedReason": "DoD too generic — spell out the acceptance criteria.",
  • "returnedAt": "2026-08-02T14:00:00.000Z",
  • "archivedAt": null,
  • "archivedReason": null,
  • "createdAt": "2026-07-25T09:00:00.000Z",
  • "updatedAt": "2026-07-25T09:40:00.000Z"
}

修正草稿 story 的标题和/或描述

仅限没有执行中任务的 draft story;以 PO 为参与者写入 backlog.story_updated(RN-727)。状态为 ready 的也可以,前提是 questionId 引用了一个用户已回答的未决问题(RN-859)。

Authorizations:
service-token
path Parameters
storyId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
title
string
description
string
questionId
string <uuid>

RN-859(ADR 0214):一个用户已经回答过的未决问题——只有这样,ready story(没有执行中的任务)才能被修正。

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "title": "Register a user",
  • "description": "As a visitor, I want to sign up.",
  • "questionId": "ffa0420e-f70b-4e5b-99a0-434bff860467"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000HISTORIA000000001",
  • "epicId": "01JC4Z0000EPICO000000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "title": "Add item to cart",
  • "description": "As a buyer, I want to gather items before paying.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "businessRuleIds": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "moduleIds": [
    ],
  • "status": "ready",
  • "proposedReady": true,
  • "returnedReason": "DoD too generic — spell out the acceptance criteria.",
  • "returnedAt": "2026-08-02T14:00:00.000Z",
  • "archivedAt": null,
  • "archivedReason": null,
  • "createdAt": "2026-07-25T09:00:00.000Z",
  • "updatedAt": "2026-07-25T09:40:00.000Z"
}

将 story 与它所涉及的模块关联

这是交叉校验:当前映射中不存在的模块会变成一项架构待办,而不是悄无声息地溜过去。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
storyId
required
string <uuid>
moduleIds
required
数组:strings

来自当前 module_map 的名称。不存在的模块会变成一项架构待办。

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "storyId": "01JC4Z0000HISTORIA000000001",
  • "moduleIds": [
    ]
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000HISTORIA000000001",
  • "epicId": "01JC4Z0000EPICO000000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "title": "Add item to cart",
  • "description": "As a buyer, I want to gather items before paying.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "businessRuleIds": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "moduleIds": [
    ],
  • "status": "ready",
  • "proposedReady": true,
  • "returnedReason": "DoD too generic — spell out the acceptance criteria.",
  • "returnedAt": "2026-08-02T14:00:00.000Z",
  • "archivedAt": null,
  • "archivedReason": null,
  • "createdAt": "2026-07-25T09:00:00.000Z",
  • "updatedAt": "2026-07-25T09:40:00.000Z"
}

在 story 内创建任务

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
storyId
required
string <uuid>
title
required
string
description
string

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "storyId": "01JC4Z0000HISTORIA000000001",
  • "title": "Endpoint POST /cart/items",
  • "description": "Accepts SKU and quantity; validates stock."
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000TAREFA00000000001",
  • "storyId": "01JC4Z0000HISTORIA000000001",
  • "title": "POST /cart/items endpoint",
  • "description": "Accepts SKU and quantity; validates stock.",
  • "status": "in_progress",
  • "assignedTo": "dev-api",
  • "blocked": false,
  • "blockedReason": null,
  • "blockedOrigin": null,
  • "gateStatus": null,
  • "gateCorrectionCount": 0,
  • "module": "api",
  • "createdAt": "2026-07-25T10:00:00.000Z",
  • "updatedAt": "2026-07-25T12:30:00.000Z"
}

将任务标记为阻塞,并附上原因

没有自动解除阻塞:解除阻塞的是人,通过人工路由。正是这一点阻止了代理无限空转。

Authorizations:
service-token
path Parameters
sessionId
required
string
taskId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
agentId
required
string
reason
required
string
diagnosis
required
string

自由文本诊断——对所发生情况的人类可读细节,而不是失败的结构化来源。

origin
string
枚举: "infra" "modelo" "codigo" "politica"

失败的来源:infra、modelo、codigo 或 politica。绝不通过排除法——这是 ADR 0020 的教训,由 QA Lead 在 ADR 0038 中提升了一个层次。可选:并非每个调用点都知道来源。

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "agentId": "dev-api",
  • "reason": "Gate correction cap reached.",
  • "diagnosis": "Correction cycle exhausted without exit 0.",
  • "origin": "infra"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000TAREFA00000000001",
  • "storyId": "01JC4Z0000HISTORIA000000001",
  • "title": "POST /cart/items endpoint",
  • "description": "Accepts SKU and quantity; validates stock.",
  • "status": "in_progress",
  • "assignedTo": "dev-api",
  • "blocked": false,
  • "blockedReason": null,
  • "blockedOrigin": null,
  • "gateStatus": null,
  • "gateCorrectionCount": 0,
  • "module": "api",
  • "createdAt": "2026-07-25T10:00:00.000Z",
  • "updatedAt": "2026-07-25T12:30:00.000Z"
}

开启任务的 gate 流水线,从 QA 开始

在 dev agent 的 PR 准备好评审时调用。

Authorizations:
service-token
path Parameters
sessionId
required
string
taskId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
agentId
required
string

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "agentId": "dev-api"
}

响应示例

Content type
application/json
{
  • "gateStatus": "awaiting_qa"
}

随着工作推进移动任务状态

Authorizations:
service-token
path Parameters
sessionId
required
string
taskId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
agentId
required
string

只有认领了任务的代理才能移动它。

status
required
string
枚举: "todo" "in_progress" "in_review" "done"

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "agentId": "dev-api",
  • "status": "in_review"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000TAREFA00000000001",
  • "storyId": "01JC4Z0000HISTORIA000000001",
  • "title": "POST /cart/items endpoint",
  • "description": "Accepts SKU and quantity; validates stock.",
  • "status": "in_progress",
  • "assignedTo": "dev-api",
  • "blocked": false,
  • "blockedReason": null,
  • "blockedOrigin": null,
  • "gateStatus": null,
  • "gateCorrectionCount": 0,
  • "module": "api",
  • "createdAt": "2026-07-25T10:00:00.000Z",
  • "updatedAt": "2026-07-25T12:30:00.000Z"
}

在短暂的网络/提供商故障后解除任务阻塞

由 engine 的重试任务调用(最多 3 次,分别在 1、3 和 10 分钟后)。与人工解除阻塞相同的用例,参与者为 system;已不再阻塞的任务保持不变。

Authorizations:
service-token
path Parameters
sessionId
required
string
taskId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
agentId
required
string

因短暂失败而安排了重试的 dev agent。

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "agentId": "dev-api"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000TAREFA00000000001",
  • "storyId": "01JC4Z0000HISTORIA000000001",
  • "title": "POST /cart/items endpoint",
  • "description": "Accepts SKU and quantity; validates stock.",
  • "status": "in_progress",
  • "assignedTo": "dev-api",
  • "blocked": false,
  • "blockedReason": null,
  • "blockedOrigin": null,
  • "gateStatus": null,
  • "gateCorrectionCount": 0,
  • "module": "api",
  • "createdAt": "2026-07-25T10:00:00.000Z",
  • "updatedAt": "2026-07-25T12:30:00.000Z"
}

原子地认领该模块下一个可认领的任务

按设计是原子的:同一模块上有多个 dev agent 时,两次并发认领不可能返回同一个任务。没有可用任务时返回空,而不是错误。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
module
required
string

只有此模块的任务参与抽取。

agentId
required
string

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "module": "api",
  • "agentId": "dev-api"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000TAREFA00000000001",
  • "storyId": "01JC4Z0000HISTORIA000000001",
  • "title": "POST /cart/items endpoint",
  • "description": "Accepts SKU and quantity; validates stock.",
  • "status": "in_progress",
  • "assignedTo": "dev-api",
  • "blocked": false,
  • "blockedReason": null,
  • "blockedOrigin": null,
  • "gateStatus": null,
  • "gateCorrectionCount": 0,
  • "module": "api",
  • "createdAt": "2026-07-25T10:00:00.000Z",
  • "updatedAt": "2026-07-25T12:30:00.000Z"
}

列出项目中由 dev agent 持有的进行中任务

未阻塞且不在 PR gate 中;除非会话是执行会话,否则为空。engine 在停止执行时使用它,以阻塞那些没有存活 dev agent 持有的任务。

Authorizations:
service-token
path Parameters
sessionId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

报告会话进程已在 engine 中终止

只有不是由 api 引起的终止才会到达这里——崩溃、kill、heartbeat_timeout、防御性关闭。由 api 自己计划的停止不经过这里:engine 已经通过 outbox 得知,再报告回来只是回声。

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
to
required
string
枚举: "closing" "closed" "closed_abnormally"

closing 不是终止状态:它表示“我正在释放这个会话”。如果另一个副本接管了它,它会继续存活;如果在超时前没有人接管,排空过程会发送 closed_abnormally。created 和 active 被排除在外,因为进入它们是 api 做出的决定,绝不是由 engine 报告终止而来。

reason
string

终止的来源,而不是通过排除法得出的诊断。

响应

请求示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "to": "closed_abnormally",
  • "reason": "heartbeat_timeout"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "status": "active",
  • "kind": "criativa",
  • "name": "Cart checkout",
  • "nextSeq": 42,
  • "createdAt": "2026-07-27T14:03:22.187Z",
  • "updatedAt": "2026-07-27T14:31:09.004Z",
  • "closedAt": null,
  • "terminationReason": null,
  • "traceParent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

LLM

列出每个 LLM 提供商能做什么,与模型无关

九个提供商能力(ADR 0041)的提供商层,读取自处理调用的同一批实例。只有经真实 API 验证的能力才为 true。界面在为 binding 提供路由偏好之前从这里读取 routingPreference(ADR 0166)。

Authorizations:
bearer

响应

响应示例

Content type
application/json
[
  • {
    }
]

解析代理使用哪个模型,以及它的来源

代理 → 区域 → 项目 → workspace 级联,不含会话:这是代理在项目上的配置,而不是某次特定对话的配置。origin: "agent" 表示该代理偏离了其区域的默认值;任何其他来源都表示它在继承。

Authorizations:
bearer
path Parameters
projectId
required
string
agentSlug
required
string
示例: dev-api

响应

响应示例

Content type
application/json
{
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "origin": "project",
  • "routingPreference": null,
  • "skipped": [
    ],
  • "herdadoDoLead": "secops"
}

在本项目中固定代理的模型

适用于本项目中所有没有自身 binding 的会话,且仅适用于这些会话——在 ADR 0064 之前 binding 是全局的,也会影响其他项目。正是这样才能在同一项目中给 Psychologist 一个便宜的模型、给 Architect 一个昂贵的模型,也正是这样代理才能偏离其区域的默认值。

Authorizations:
bearer
path Parameters
projectId
required
string
agentSlug
required
string
示例: dev-api
Request Body schema: application/json
required
modelId
required
string <uuid>

要固定到此范围的模型。必须存在于 GET /models 中。

routingPreference
string or null
枚举: "price" "throughput" "latency"

中转平台如何选择服务该模型的上游(ADR 0166,RN-583)。缺省时,若新模型的提供商接受则保留已存储的值,否则清除;null 清除它;为提供商未声明 routingPreference 能力(GET /llm/provider-capabilities)的模型设置值会以 422 拒绝。它随此 binding 一起传递:从不独立级联。

响应

请求示例

Content type
application/json
{
  • "modelId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "routingPreference": "throughput"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000BINDING00000000001",
  • "scope": "project",
  • "scopeId": "01JC4Z0000PROJETO0000000001",
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "routingPreference": null,
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "createdAt": "2026-07-11T09:00:00.000Z",
  • "updatedAt": "2026-07-11T09:00:00.000Z"
}

让代理恢复继承区域的模型

删除代理的 binding——而不是把区域的模型复制进去。复制在界面上看起来一样,实则不然:它会变成一份副本,区域的下一次变更会悄无声息地把这个代理落下。已在继承时返回 404。

Authorizations:
bearer
path Parameters
projectId
required
string
agentSlug
required
string
示例: dev-api

响应

按代理细分项目在过去 30 天的花费

一个滑动的 30 天窗口,而不是当前自然月:这是界面显示的标签,若用自然月,估算会在每月 1 日因翻页而骤降,而不是因为使用量变化。只计入 actor_kind = agent(RN-038)。从未运行过的代理不会出现在列表中——界面为其显示一个短横线,这与零不同。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

解析区域的默认模型是什么,以及它的来源

lead 与区域子代理共享的默认值。origin: "area" 表示有人为这个区域做了选择;任何其他来源都表示区域本身从项目或 workspace 继承。

Authorizations:
bearer
path Parameters
projectId
required
string
areaKey
required
string
示例: qa

响应

响应示例

Content type
application/json
{
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "origin": "project",
  • "routingPreference": null,
  • "skipped": [
    ],
  • "herdadoDoLead": "secops"
}

设置区域的默认模型

适用于 lead 以及该区域中所有没有自身 binding 的子代理(RN-102)。需要 maintainer,因为它一次影响整个区域,而选择模型就是决定花费——与并行度上限的理由相同。

Authorizations:
bearer
path Parameters
projectId
required
string
areaKey
required
string
示例: qa
Request Body schema: application/json
required
modelId
required
string <uuid>

要固定到此范围的模型。必须存在于 GET /models 中。

routingPreference
string or null
枚举: "price" "throughput" "latency"

中转平台如何选择服务该模型的上游(ADR 0166,RN-583)。缺省时,若新模型的提供商接受则保留已存储的值,否则清除;null 清除它;为提供商未声明 routingPreference 能力(GET /llm/provider-capabilities)的模型设置值会以 422 拒绝。它随此 binding 一起传递:从不独立级联。

响应

请求示例

Content type
application/json
{
  • "modelId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "routingPreference": "throughput"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000BINDING00000000001",
  • "scope": "project",
  • "scopeId": "01JC4Z0000PROJETO0000000001",
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "routingPreference": null,
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "createdAt": "2026-07-11T09:00:00.000Z",
  • "updatedAt": "2026-07-11T09:00:00.000Z"
}

让区域恢复继承项目的模型

区域不再有自己的默认值,开始从项目(或 workspace)继承。已偏离的代理继续偏离:它们的 binding 是另一个,删除这一个无法替它们做决定。

Authorizations:
bearer
path Parameters
projectId
required
string
areaKey
required
string
示例: qa

响应

读取项目预算以及已花费的金额

数值以微美元计。需要 maintainer——这是成本信息。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000ORCAMENTO000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": null,
  • "limitMicros": 50000000,
  • "spentMicros": 12400000,
  • "policy": "block",
  • "lastThresholdNotified": 70,
  • "createdAt": "2026-07-12T08:00:00.000Z",
  • "updatedAt": "2026-07-27T15:00:00.000Z"
}

设置项目花费上限

限额以美元传入并转换为微美元。在 policy=block 下,会超出上限的调用会被拒绝,而不仅仅是被记录。

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
limitUsd
required
number >= 0

上限,以美元计——契约中唯一以美元表述的地方,因为那是人会输入的单位。api 将其转换为微美元,响应以微美元返回。

policy
required
string
枚举: "block" "allow"

block 会在调用将超出上限时拒绝它;allow 会放行并只发出警告。

响应

请求示例

Content type
application/json
{
  • "limitUsd": 50,
  • "policy": "block"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000ORCAMENTO000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": null,
  • "limitMicros": 50000000,
  • "spentMicros": 12400000,
  • "policy": "block",
  • "lastThresholdNotified": 70,
  • "createdAt": "2026-07-12T08:00:00.000Z",
  • "updatedAt": "2026-07-27T15:00:00.000Z"
}

读取项目的模型 binding

此范围的原始 binding——如果项目只从 workspace 继承则为 null。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000BINDING00000000001",
  • "scope": "project",
  • "scopeId": "01JC4Z0000PROJETO0000000001",
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "routingPreference": null,
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "createdAt": "2026-07-11T09:00:00.000Z",
  • "updatedAt": "2026-07-11T09:00:00.000Z"
}

设置项目的模型

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
modelId
required
string <uuid>

要固定到此范围的模型。必须存在于 GET /models 中。

routingPreference
string or null
枚举: "price" "throughput" "latency"

中转平台如何选择服务该模型的上游(ADR 0166,RN-583)。缺省时,若新模型的提供商接受则保留已存储的值,否则清除;null 清除它;为提供商未声明 routingPreference 能力(GET /llm/provider-capabilities)的模型设置值会以 422 拒绝。它随此 binding 一起传递:从不独立级联。

响应

请求示例

Content type
application/json
{
  • "modelId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "routingPreference": "throughput"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000BINDING00000000001",
  • "scope": "project",
  • "scopeId": "01JC4Z0000PROJETO0000000001",
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "routingPreference": null,
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "createdAt": "2026-07-11T09:00:00.000Z",
  • "updatedAt": "2026-07-11T09:00:00.000Z"
}

一次读取解析多个代理和区域的模型

GET .../agent-bindings/:agentSlug 和 GET .../area-bindings/:areaKey 的批量形式:每个请求的键得到的值与其单键路由的回答完全相同(相同的级联、相同的来源,没有任何层级有模型时为 null)。它的存在让 Settings 标签页用一次请求而不是 20 次读取 20 个已解析的 binding——速率限制是按用户计的。键以逗号分隔并去重,格式错误的键或总数超过 64 个键返回 400,绝不悄悄丢弃。

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
agents
string
示例: agents=criativo,po,dev-lead

以逗号分隔的代理 slug。

areas
string
示例: areas=dev,qa,infra

以逗号分隔的区域键。

响应

响应示例

Content type
application/json
{
  • "agents": [
    ],
  • "areas": [
    ]
}

列出项目所属 workspace 中已激活的模型

local 类别是 Ollama 的模型,不花钱;cloud 是付费 API 的模型。workspace 未激活的模型不会出现在这里,但仍保留在历史成本中——要查看它请使用目录路由。该列表属于项目的所有者 workspace:同一模型可以在一个 workspace 中开启而在相邻的 workspace 中关闭(ADR 0049)。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "local": {
    },
  • "cloud": {
    }
}

读取会话预算和累计花费

这是会话界面实时 token 计量表的数据来源。

Authorizations:
bearer
path Parameters
sessionId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000ORCAMENTO000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": null,
  • "limitMicros": 50000000,
  • "spentMicros": 12400000,
  • "policy": "block",
  • "lastThresholdNotified": 70,
  • "createdAt": "2026-07-12T08:00:00.000Z",
  • "updatedAt": "2026-07-27T15:00:00.000Z"
}

设置会话花费上限

与项目预算相同的美元到微美元转换。

Authorizations:
bearer
path Parameters
sessionId
required
string
Request Body schema: application/json
required
limitUsd
required
number >= 0

上限,以美元计——契约中唯一以美元表述的地方,因为那是人会输入的单位。api 将其转换为微美元,响应以微美元返回。

policy
required
string
枚举: "block" "allow"

block 会在调用将超出上限时拒绝它;allow 会放行并只发出警告。

响应

请求示例

Content type
application/json
{
  • "limitUsd": 50,
  • "policy": "block"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000ORCAMENTO000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": null,
  • "limitMicros": 50000000,
  • "spentMicros": 12400000,
  • "policy": "block",
  • "lastThresholdNotified": 70,
  • "createdAt": "2026-07-12T08:00:00.000Z",
  • "updatedAt": "2026-07-27T15:00:00.000Z"
}

与会话的模型对话,以流式返回响应

Server-Sent Events。delta 帧携带增量文本,done 以 token 和成本计费收尾。metering_failed 帧表示响应已发出但成本没有计入——失败会显现出来而不是消失。如果在 policy=block 下超出预算,流会携带 error 且没有 delta。此路由不携带代理:它把文本单独发送给绑定的模型,没有历史也没有系统提示词。在从未激活过任何代理的 consultiva 会话中,它会在产生任何效果之前被拒绝(RN-682)——请改用 .../agents/:agent/message 与代理对话。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
text
required
string

用户的消息。响应以 SSE 流返回。

响应

请求示例

Content type
application/json
{
  • "text": "Summarize what we have already decided about checkout."
}

解析会话使用哪个模型,以及它的来源

返回由级联解析得出的 binding,而不是会话的原始 binding:没有自身 binding 的会话使用项目的 binding,在这里回答 null 就是对正确问题的错误回答。origin 字段说明该值来自哪个范围。

agentId 是可选的,表示此刻在会话中真正活跃的代理(与 RunLlmTurnUseCase 运行回合时使用的相同)——没有它,级联只能看到 会话→项目→workspace(加上固定回落到 Creative),在 handoff 之后永远无法反映 PO/Architect/Dev Lead/区域。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
query Parameters
agentId
string

此会话中当前活跃的代理(例如 “po”、“arquiteto”、“dev-lead”)。

响应

响应示例

Content type
application/json
{
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "origin": "project",
  • "routingPreference": null,
  • "skipped": [
    ],
  • "herdadoDoLead": "secops"
}

为此会话固定模型

在会话存续期间优先于级联中的其他一切。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
modelId
required
string <uuid>

要固定到此范围的模型。必须存在于 GET /models 中。

routingPreference
string or null
枚举: "price" "throughput" "latency"

中转平台如何选择服务该模型的上游(ADR 0166,RN-583)。缺省时,若新模型的提供商接受则保留已存储的值,否则清除;null 清除它;为提供商未声明 routingPreference 能力(GET /llm/provider-capabilities)的模型设置值会以 422 拒绝。它随此 binding 一起传递:从不独立级联。

响应

请求示例

Content type
application/json
{
  • "modelId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "routingPreference": "throughput"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000BINDING00000000001",
  • "scope": "project",
  • "scopeId": "01JC4Z0000PROJETO0000000001",
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "routingPreference": null,
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "createdAt": "2026-07-11T09:00:00.000Z",
  • "updatedAt": "2026-07-11T09:00:00.000Z"
}

按代理细分会话花费

数据一直在 token_usage 中,但没有聚合也没有路由,团队面板就无法显示每张卡片的成本。所需角色与会话预算相同。

Authorizations:
bearer
path Parameters
sessionId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

我自己在此项目中的消耗,按会话和按天

面向成员的视图。只有调用方自己的记录——参与者来自已认证的令牌,没有可替换它的参数。以 token 和估算成本呈现,不按提供商或凭据细分:运行的密钥属于所有者(RN-058),其账单也属于所有者(RN-060)。提供商维度在所有者的报告中才存在(ADR 0076),从这里仍不可达——此路由没有维度参数,仓储类型也拒绝这种组合(RN-187)。代理不计入:token_usage 记录的是谁花费了,而不是谁下令花费。

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
dias
string

滑动窗口。默认 30,最大 180。

响应

响应示例

Content type
application/json
{
  • "projectId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "dias": 30,
  • "actorId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "totalMicros": 1250000,
  • "assinaturaMicros": 0,
  • "inputTokens": 120000,
  • "outputTokens": 35000,
  • "chamadas": 42,
  • "porSessao": [
    ],
  • "porDia": [
    ]
}

The project's total spend and cost by agent and area

The MEMBER's view of the PROJECT (RN-953, ADR 0233, revising 0063): total and cost per agent/area, NEVER provider or credential — the route has no dimension parameter and never asks for provider.

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
dias
string

滑动窗口。默认 30,最大 180。

响应

响应示例

Content type
application/json
{
  • "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8",
  • "dias": 30,
  • "totalMicros": 1250000,
  • "assinaturaMicros": 0,
  • "inputTokens": 120000,
  • "outputTokens": 35000,
  • "chamadas": 42,
  • "porAgente": [
    ],
  • "porArea": [
    ]
}

所有者的密钥花费了多少,按提供商和按月

之所以存在,是因为代理花费的密钥属于 workspace 所有者(RN-058)——付账的人需要看到账单。按提供商分组,因为那是凭据的单位,并把代理花出去的与人在聊天中花出去的分开:两者出自同一把密钥,回答的是不同的问题。不返回任何机密。

Authorizations:
bearer
path Parameters
workspaceId
required
string
query Parameters
meses
required
string

响应

响应示例

Content type
application/json
{
  • "workspaceId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "ownerId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "meses": 6,
  • "totalMicros": 1250000,
  • "porProvider": [
    ]
}

创建一个待处理的拉取请求——尚不下载任何东西

两个显式步骤中的第一步:此调用只记录意图,状态为 pending_confirmation。在另行调用 POST .../pull-requests/:id/confirm 之前不会拉取任何东西——产品绝不会运行自动的、静默的拉取。

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
repoId
required
string

Hugging Face Hub 上的 <publisher>/<modelo>。

estimatedSizeBytes
number

当 Hub 公布了大小时来自搜索结果——绝不在客户端凭猜测估算。

响应

请求示例

Content type
application/json
{
  • "repoId": "meta-llama/Llama-3.1-8B-Instruct-GGUF",
  • "estimatedSizeBytes": 4900000000
}

响应示例

Content type
application/json
{
  • "id": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "workspaceId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "requestedBy": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "repoId": "meta-llama/Llama-3.1-8B-Instruct-GGUF",
  • "estimatedSizeBytes": null,
  • "status": "pending_confirmation",
  • "confirmedAt": null,
  • "failedReason": null,
  • "createdAt": "2026-08-26T12:00:00.000Z",
  • "updatedAt": "2026-08-26T12:00:00.000Z"
}

拉取请求的状态,供前端轮询

Authorizations:
bearer
path Parameters
workspaceId
required
string
id
required
string

响应

响应示例

Content type
application/json
{
  • "id": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "workspaceId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "requestedBy": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "repoId": "meta-llama/Llama-3.1-8B-Instruct-GGUF",
  • "estimatedSizeBytes": null,
  • "status": "pending_confirmation",
  • "confirmedAt": null,
  • "failedReason": null,
  • "createdAt": "2026-08-26T12:00:00.000Z",
  • "updatedAt": "2026-08-26T12:00:00.000Z"
}

第二次确认——真正执行拉取

将 pending_confirmation → confirmed → pulling,调用 Ollama 守护进程,成功后将模型 upsert 到目录(models)并为此 workspace 激活它。失败时请求以 failed 结束,附带声明其来源的原因(infra | model | code | policy)——绝不是静默失败。此调用在整个拉取过程中同步运行(原因见用例);请使用下面的 GET 路由轮询,而不要一直保持此连接。

Authorizations:
bearer
path Parameters
workspaceId
required
string
id
required
string

响应

响应示例

Content type
application/json
{
  • "id": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "workspaceId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "requestedBy": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "repoId": "meta-llama/Llama-3.1-8B-Instruct-GGUF",
  • "estimatedSizeBytes": null,
  • "status": "pending_confirmation",
  • "confirmedAt": null,
  • "failedReason": null,
  • "createdAt": "2026-08-26T12:00:00.000Z",
  • "updatedAt": "2026-08-26T12:00:00.000Z"
}

Lists the LLM providers the workspace owner has a key for

The owner of record (workspaces.created_by) is whose key the agents spend (RN-058). Only provider NAMES — never a secret, id or date. ollama (local, no key) never appears.

Authorizations:
bearer
path Parameters
workspaceId
required
string

响应

响应示例

Content type
application/json
{
  • "providers": [
    ]
}

读取 workspace 的模型 binding

此范围的原始 binding。它是级联的根。

Authorizations:
bearer
path Parameters
workspaceId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000BINDING00000000001",
  • "scope": "project",
  • "scopeId": "01JC4Z0000PROJETO0000000001",
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "routingPreference": null,
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "createdAt": "2026-07-11T09:00:00.000Z",
  • "updatedAt": "2026-07-11T09:00:00.000Z"
}

设置 workspace 的默认模型

适用于所有没有自身 binding 的项目。

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
modelId
required
string <uuid>

要固定到此范围的模型。必须存在于 GET /models 中。

routingPreference
string or null
枚举: "price" "throughput" "latency"

中转平台如何选择服务该模型的上游(ADR 0166,RN-583)。缺省时,若新模型的提供商接受则保留已存储的值,否则清除;null 清除它;为提供商未声明 routingPreference 能力(GET /llm/provider-capabilities)的模型设置值会以 422 拒绝。它随此 binding 一起传递:从不独立级联。

响应

请求示例

Content type
application/json
{
  • "modelId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "routingPreference": "throughput"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000BINDING00000000001",
  • "scope": "project",
  • "scopeId": "01JC4Z0000PROJETO0000000001",
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "routingPreference": null,
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "createdAt": "2026-07-11T09:00:00.000Z",
  • "updatedAt": "2026-07-11T09:00:00.000Z"
}

Sets a model's curated billing mark (api | subscription | free)

Same curation level as the pricing route. subscription makes the spend report show the cost apart from the US$ paid (RN-954). Never re-prices the past.

Authorizations:
bearer
path Parameters
modelId
required
string
Request Body schema: application/json
required
billing
required
string
枚举: "api" "subscription" "free"

响应

请求示例

Content type
application/json
{
  • "billing": "subscription"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000MODELO00000000001",
  • "provider": "anthropic",
  • "name": "claude-opus-4-8",
  • "displayName": "Claude Opus 4.8",
  • "inputPricePerMillionMicros": 15000000,
  • "outputPricePerMillionMicros": 75000000,
  • "contextWindow": 200000,
  • "supportsToolCalling": true,
  • "supportsStreaming": true,
  • "supportsVision": false,
  • "supportsReasoning": true,
  • "generatesImage": false,
  • "reasoningBudget": 2048,
  • "manualPricing": true,
  • "availability": "available",
  • "billing": "api",
  • "lastSeenAt": "2026-07-30T03:00:00.000Z",
  • "createdAt": "2026-07-01T00:00:00.000Z",
  • "updatedAt": "2026-07-01T00:00:00.000Z"
}

模型价格变更的历史

最新的在前。这是不可变的日志:绝不执行 UPDATE,每条记录都携带前/后值对,因此审计不依赖于从上一条记录重建“之前”的值。

Authorizations:
bearer
path Parameters
modelId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

修正模型的价格

从现在起生效,绝不重新为过去定价:每条 token_usage 记录都保留产生其成本的价格。变更会连同前/后值对一起记录——可通过历史路由查询。

Authorizations:
bearer
path Parameters
modelId
required
string
Request Body schema: application/json
required
inputPricePerMillionMicros
required
number

每百万输入 token 的价格,以微美元计。

outputPricePerMillionMicros
required
number

每百万输出 token 的价格,以微美元计。

响应

请求示例

Content type
application/json
{
  • "inputPricePerMillionMicros": 2500000,
  • "outputPricePerMillionMicros": 10000000
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000MODELO00000000001",
  • "provider": "anthropic",
  • "name": "claude-opus-4-8",
  • "displayName": "Claude Opus 4.8",
  • "inputPricePerMillionMicros": 15000000,
  • "outputPricePerMillionMicros": 75000000,
  • "contextWindow": 200000,
  • "supportsToolCalling": true,
  • "supportsStreaming": true,
  • "supportsVision": false,
  • "supportsReasoning": true,
  • "generatesImage": false,
  • "reasoningBudget": 2048,
  • "manualPricing": true,
  • "availability": "available",
  • "billing": "api",
  • "lastSeenAt": "2026-07-30T03:00:00.000Z",
  • "createdAt": "2026-07-01T00:00:00.000Z",
  • "updatedAt": "2026-07-01T00:00:00.000Z"
}

在选择器中开启或关闭模型(批量)

所有者的策展,仅适用于此 workspace(ADR 0049)。只改动 isActive——availability 是同步在提供商处观测到的,是全局的,在这里不会改变。整批全有或全无:不存在的 id 会让调用失败,不应用任何一行。

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
modelIds
required
数组:strings <uuid> [ items <uuid > ]

要开启或关闭的模型。整批全有或全无。

isActive
required
boolean

true 让模型出现在选择器中并能接收新的 binding。不改动 availability,那是同步在提供商处观测到的。

响应

请求示例

Content type
application/json
{
  • "modelIds": [
    ],
  • "isActive": true
}

响应示例

Content type
application/json
[
  • {
    }
]

列出整个目录,包括未激活和不可用的模型

策展界面。同步发现的模型以 isActive: false 进入,在有人激活它之前只出现在这里;从提供商消失的模型会带有 availability: "unavailable",且绝不删除,因为 binding 和成本历史都指向它。isActive 是针对此 workspace 的(ADR 0049);availability 是全局的,因为它是同步在提供商处观测到的。

Authorizations:
bearer
path Parameters
workspaceId
required
string

响应

响应示例

Content type
application/json
{
  • "local": {
    },
  • "cloud": {
    }
}

立即强制执行定期任务所做的目录同步

与 engine 调度的内部路由相同的用例——策展界面的刷新按钮没有自己的路径,因此绝不会出现两个可能产生分歧的对账。

Authorizations:
bearer

响应

响应示例

Content type
application/json
{
  • "porProvider": [
    ]
}

标记 workspace 将每个模型用于什么(批量)

没有任何目录会公布的维度:“适合写代码”不是任何提供商声明的能力,而是运营者的意见——且仅适用于此 workspace(ADR 0049)。与激活相互独立的维度:标记某种用途不会在选择器中开启模型,更改用途也不会关闭已开启的模型。用途列表会替换之前的列表。

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
modelIds
required
数组:strings <uuid> [ items <uuid > ]

要标记的模型。整批全有或全无。

uses
required
数组:strings
项 枚举: "codigo" "documentacao" "analise" "imagem" "conversa"

完整的用途列表——替换之前的列表,而不是追加。空列表会取消全部标记。封闭词汇:词汇之外的用途会让调用失败,因为自由文本会在同一个过滤器中出现 code、coding 和 código。

响应

请求示例

Content type
application/json
{
  • "modelIds": [
    ],
  • "uses": [
    ]
}

响应示例

Content type
application/json
[
  • {
    }
]

按模型、提供商、项目、参与者和天细分 workspace 的花费

面向所有者的视图。提供商维度回来了(ADR 0076,RN-186),并且在这里而不是在成员的路由上,因为按提供商细分就是按凭据细分——而凭据是付钱的人的事(RN-060)。补充 credential-spend,后者继续回答账单问题(按月,并与当前存在的密钥对应)。人和代理也按 actor_kind 分成单独的块。以天为单位的滑动窗口,每日序列是稠密的——没有花费的日子以零出现,否则迷你图会在节奏上说谎。

Authorizations:
bearer
path Parameters
workspaceId
required
string
query Parameters
dias
string

滑动窗口。默认 30,最大 180。

projectId
string

Slice to ONE project of this workspace (RN-952). A project from another workspace answers 404.

响应

响应示例

Content type
application/json
{
  • "workspaceId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "ownerId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "dias": 30,
  • "projectId": { },
  • "totalMicros": 1250000,
  • "assinaturaMicros": 0,
  • "inputTokens": 120000,
  • "outputTokens": 35000,
  • "chamadas": 42,
  • "porModelo": [
    ],
  • "porProvider": [
    ],
  • "porProjeto": [
    ],
  • "porSessao": [
    ],
  • "porAtor": [
    ],
  • "porOwner": [
    ],
  • "porAgente": [
    ],
  • "porDia": [
    ]
}

My own consumption in this workspace, summed by project

The non-owner's global page (RN-953). Only the caller's rows, by PROJECT and by day, without provider or credential.

Authorizations:
bearer
path Parameters
workspaceId
required
string
query Parameters
dias
string

滑动窗口。默认 30,最大 180。

响应

响应示例

Content type
application/json
{
  • "workspaceId": "ef0efa32-d1c1-43d4-a5e2-fe7b4f00403c",
  • "dias": 30,
  • "actorId": "d2f1b55c-8cee-4a0d-af57-aebaeff77518",
  • "totalMicros": 1250000,
  • "assinaturaMicros": 0,
  • "inputTokens": 120000,
  • "outputTokens": 35000,
  • "chamadas": 42,
  • "porProjeto": [
    ],
  • "porDia": [
    ]
}

项目

按 id 返回项目

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000PROJETO0000000001",
  • "workspaceId": "01JC4Z0000WORKSPACE00000001",
  • "name": "Checkout",
  • "slug": "checkout",
  • "workspaceDirName": "checkout-3f2b1c8e",
  • "executionMode": "container",
  • "workspacePath": null,
  • "workspaceVerifiedAt": null,
  • "mirrorPath": null,
  • "language": "pt-BR",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "taskBudgetMicros": 500000,
  • "maxConsecutiveBlocked": 3,
  • "storyPromotion": "auto",
  • "createdAt": "2026-07-21T11:00:00.000Z",
  • "updatedAt": "2026-07-21T11:00:00.000Z"
}

修改项目的名称或 slug

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
name
string >= 2 characters
slug
string^[a-z0-9]+(-[a-z0-9]+)*$

kebab-case。在 workspace 内唯一。

maxConsecutiveBlocked
number

熔断器(Phase 12b——RN-047):连续多少个任务以阻塞结束会让该模块的 dev agent 停在 idle_tripped。省略时使用领域默认值(DEFAULT_MAX_CONSECUTIVE_BLOCKED)。从下一次激活执行起生效——不影响已在运行的代理。

storyPromotion
string
枚举: "manual" "auto"

谁把 story 从 draft 提升为 ready(Phase 12c——RN-048)。auto(自 RN-659 起为新项目的默认值):完整的 story 一出生就是 ready,没有人工步骤。manual:PO 提议,由你在 Backlog 标签页中决定。更改默认值并没有改写任何已有项目。领域校验(DoD/DoR/RF/规则/模块)在两种模式下完全相同;模式只改变由谁触发。

language
string <= 35 characters

项目的语言(RN-619)——共享制品和没有人类作者的回合使用它。服务器能识别的任何 BCP-47 代码,以规范形式存储;无法识别的返回 400。省略时,项目以其创建者的有效回复语言开始(RN-618:账户选择 > 已确认的检测 > 界面语言)。

响应

请求示例

Content type
application/json
{
  • "name": "Checkout",
  • "slug": "checkout",
  • "maxConsecutiveBlocked": 3,
  • "storyPromotion": "auto",
  • "language": "pt-BR"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000PROJETO0000000001",
  • "workspaceId": "01JC4Z0000WORKSPACE00000001",
  • "name": "Checkout",
  • "slug": "checkout",
  • "workspaceDirName": "checkout-3f2b1c8e",
  • "executionMode": "container",
  • "workspacePath": null,
  • "workspaceVerifiedAt": null,
  • "mirrorPath": null,
  • "language": "pt-BR",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "taskBudgetMicros": 500000,
  • "maxConsecutiveBlocked": 3,
  • "storyPromotion": "auto",
  • "createdAt": "2026-07-21T11:00:00.000Z",
  • "updatedAt": "2026-07-21T11:00:00.000Z"
}

删除项目

会连同其会话、事件日志和提议的操作一起删除。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000PROJETO0000000001",
  • "workspaceId": "01JC4Z0000WORKSPACE00000001",
  • "name": "Checkout",
  • "slug": "checkout",
  • "workspaceDirName": "checkout-3f2b1c8e",
  • "executionMode": "container",
  • "workspacePath": null,
  • "workspaceVerifiedAt": null,
  • "mirrorPath": null,
  • "language": "pt-BR",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "taskBudgetMicros": 500000,
  • "maxConsecutiveBlocked": 3,
  • "storyPromotion": "auto",
  • "createdAt": "2026-07-21T11:00:00.000Z",
  • "updatedAt": "2026-07-21T11:00:00.000Z"
}

项目容器的状态(当前的镜像决定)

当状态为 sem_decisao 时,项目容器不会启动,Code 标签页返回 409——这就是 RN-105 的 gate。查看该状态所需的权限与查看项目相同,即 viewer。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "status": "sem_decisao",
  • "decisao": {
    },
  • "version": 0,
  • "eventId": "01JC4Z0000EVENTO000000001",
  • "decidedAt": { }
}

项目容器的生命周期(登记状态)

项目从未置备时为 null——这是目前的常见情况,因为还没有真正的编排器转换这张表(RN-243/RN-267)。status/imageVersion/resources 是登记的内容;observado 是 Docker 守护进程此刻报告的内容,经由 broker 查询(ADR 0130)。两者绝不合并:从外部被杀掉的容器读起来是登记为 running、观测为 exited。当无法查看时,observado 为 null,naoObservado 说明原因——它绝不继承登记状态(RN-468)。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "status": "provisioning",
  • "imageVersion": 1,
  • "resources": {
    },
  • "failureReason": null,
  • "createdAt": "2019-08-24T14:15:22Z",
  • "statusChangedAt": "2019-08-24T14:15:22Z",
  • "observado": {
    },
  • "naoObservado": "broker-nao-configurado",
  • "detalheDaObservacao": null
}

Declared network of the container (artifact.container_network)

The current declaration (ports on 127.0.0.1, DNS, extra hosts), or null. It is what was DECLARED; it only takes effect when the container is recreated (container_recreate).

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "ports": [
    ],
  • "dns": [
    ],
  • "extraHosts": [
    ],
  • "version": 1
}

Declares the container network (human only)

Emits a new version of artifact.container_network (the current one replaces the previous). Not an external effect: nothing changes in Docker until a container_recreate is approved (AT-608, RN-932). 400 rede_invalida names the field.

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
数组:objects (PortaDto)

Up to 10 TCP ports published on 127.0.0.1 only. host 1024-65535, never an installation port, no duplicates.

dns
数组:strings

Up to 3 literal IPs.

数组:objects (HostExtraDto)

Up to 10 --add-host entries: name in [a-z0-9.-], never localhost or an installation service, IPv4 literal.

响应

请求示例

Content type
application/json
{
  • "ports": [
    ],
  • "dns": [
    ],
  • "extraHosts": [
    ]
}

响应示例

Content type
application/json
{
  • "ports": [
    ],
  • "dns": [
    ],
  • "extraHosts": [
    ],
  • "version": 1
}

转换项目的执行模式

为已存在的项目迁移 execution_mode/workspacePath(RN-447..450,ADR 0111)——专用路由,与 PATCH 分开,因为它编排的不只是写一个列:它把 permissions.json 移动到新的范围根目录,在离开 container 模式时撤下容器生命周期记录,并且只要项目中有任何 dev agent 不处于空闲状态就拒绝(409),因为运行中的代理不会自行重新解析其 worktree 位置。

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
executionMode
required
string
枚举: "container" "mounted" "runner"

新的执行模式。可以与项目当前的模式相同——这种情况下,真正改变的只有 workspacePath。

workspacePath
string

用户文件夹的绝对路径——当 executionMode 为 mounted 或 runner 时必需,为 container 时拒绝。与创建时的校验相同(RN-170/RN-422/RN-423):在 mounted 中,它必须存在且可从容器内写入;在 runner 中,现在只校验格式——真正的确认来自 runner 重新连接。

响应

请求示例

Content type
application/json
{
  • "executionMode": "runner",
  • "workspacePath": "/home/you/projects/store"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000PROJETO0000000001",
  • "workspaceId": "01JC4Z0000WORKSPACE00000001",
  • "name": "Checkout",
  • "slug": "checkout",
  • "workspaceDirName": "checkout-3f2b1c8e",
  • "executionMode": "container",
  • "workspacePath": null,
  • "workspaceVerifiedAt": null,
  • "mirrorPath": null,
  • "language": "pt-BR",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "taskBudgetMicros": 500000,
  • "maxConsecutiveBlocked": 3,
  • "storyPromotion": "auto",
  • "createdAt": "2026-07-21T11:00:00.000Z",
  • "updatedAt": "2026-07-21T11:00:00.000Z"
}

列出项目成员

只包含在此处关联的人,以及该关联的角色——仅通过 workspace 进入项目的人没有记录,不会显示。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

将用户关联到项目

该角色会覆盖此人在 workspace 中的角色,两个方向都是:在这里把某人关联为 viewer 确实会在此项目上限制一个 workspace developer。有两种变动会以 403 拒绝,且在任何地方都无法启用:降级一个 workspace owner,以及修改你自己的角色——无论降级还是升级,因为自我提升正是提权的那一半。

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
userId
required
string <uuid>

要关联的用户 id。

role
required
string
枚举: "viewer" "developer" "maintainer" "owner"

此关联中的角色。在项目上,它在两个方向上都覆盖 workspace 角色——只要关联存在,有效角色就是这个,无论更高还是更低——并且有两种变动会以 403 拒绝:降级 workspace owner,以及修改你自己的角色(任一方向)。在 workspace 上它就是单纯的角色,只有上述第二条上限:你不能修改自己的角色。

响应

请求示例

Content type
application/json
{
  • "userId": "3f1b2c8e-5a4d-4b7e-9c10-2d6f8a1b4c33",
  • "role": "developer"
}

响应示例

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "userId": "01JC4Z0000USUARIO0000000002",
  • "role": "maintainer",
  • "createdAt": "2026-07-22T08:05:00.000Z"
}

解除用户与项目的关联

只移除项目关联。在 workspace 中有角色的人仍会通过继承看到项目——而由于项目角色在两个方向上都覆盖 workspace 角色,这种继承可能低于该记录所授予的角色。因此,只要净效果是降级(包括完全没有 workspace 角色的情况),移除你自己的记录就会以 403 拒绝;当 workspace 持有相同角色时移除,以及移除其他任何人,仍然可行。

Authorizations:
bearer
path Parameters
projectId
required
string
userId
required
string

响应

声明(或清除)项目的镜像目标

用户机器上的绝对路径,本地代理会把工作复制到这里(RN-515,ADR 0147)——一个位于挂载基目录之外的文件夹,这正是镜像存在的全部理由。按项目设置,绝不全局:一个全局目标会把项目 B 的制品放进项目 A 的文件夹,而用户会从内容中发现,而不是从错误中发现。mirrorPath: null 会清除它并关闭镜像——该键是必需的,省略它返回 400,因为省略字段的请求体与请求清除无法区分。null 是项目的正常状态。maintainer,与 execution-mode 和 projects-base 的最低要求相同:此路由涉及运营者自己文件系统上的路径。它只校验词法形态,并以 400 拒绝位于 workspacePath 内部或包含它的目标(同一循环的两个方向),以及 container 项目上的任何目标。它从不触碰磁盘:API 看不到目标所在的机器。写入镜像不是 proposed_action——它是用户声明的配置,不是代理请求执行操作。

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
mirrorPath
required
string or null

用户机器上的绝对路径,本地代理会把项目工作复制到这里(RN-515,ADR 0147)。发送 null——该键是必需的,省略返回 400——以清除目标并关闭镜像;null 是项目的正常状态,不是错误。只有 mounted/runner 项目可以有:在 container 中,来源是本地代理看不到的服务端托管卷,请求会以 400 拒绝并说明这一原因。API 只校验词法形态(绝对路径,不含 ../.,绝不是根目录、系统文件夹或与 Brabo 自身检出目录重叠)以及来源↔目标循环的两个方向(目标不能位于 workspacePath 内部,也不能包含它)——它从不触碰磁盘,因为它看不到目标所在的机器,与 runner 模式完全一样(RN-423)。解析符号链接是本地代理负责的那一半防护,而不是这里。

响应

请求示例

Content type
application/json
{
  • "mirrorPath": "/home/you/mirrors/store"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000PROJETO0000000001",
  • "workspaceId": "01JC4Z0000WORKSPACE00000001",
  • "name": "Checkout",
  • "slug": "checkout",
  • "workspaceDirName": "checkout-3f2b1c8e",
  • "executionMode": "container",
  • "workspacePath": null,
  • "workspaceVerifiedAt": null,
  • "mirrorPath": null,
  • "language": "pt-BR",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "taskBudgetMicros": 500000,
  • "maxConsecutiveBlocked": 3,
  • "storyPromotion": "auto",
  • "createdAt": "2026-07-21T11:00:00.000Z",
  • "updatedAt": "2026-07-21T11:00:00.000Z"
}

最近一轮镜像做了什么(RN-517)

本地代理在把工作复制到用户文件夹后通过通道推送的遥测(ADR 0147,第 7 点)——绝不进入事件日志,因为一轮镜像没有会话,而 session_events.session_id 是 NOT NULL(与把 rag_searches 做成表的理由相同)。三种答案绝不合并为一(RN-088):never(从未报告过任何一轮)、synced(最近一轮已复制——filesCopied 可能为 0,表示“看过了,没有需要复制的”)和 failed。失败绝不会抹去最近一次成功的同步,成功也绝不会抹去最近一次错误:哪个是当前状态由比较两个时间戳得出,因此界面可以说“从今天开始失败,最近一次成功复制是昨天,共 412 个文件”。lastDestination 是冻结的——在有人修改目标后它会与 mirrorPath 不同,因为授权随 join 传递,只在 runner 重连时才会改变(RN-516)。viewer,与读取项目的最低要求相同,项目本身已携带 mirrorPath。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "mirrorPath": "/home/you/mirrors/store",
  • "status": "synced",
  • "lastSyncedAt": "2026-09-07T12:04:00.000Z",
  • "filesCopied": 412,
  • "filesSkipped": 3,
  • "filesRefused": 0,
  • "lastDestination": "/home/you/mirrors/store",
  • "lastError": null,
  • "lastErrorAt": null
}

读取项目的 permissions.json

这是项目 workspace 根目录下的物理文件,而不是数据库列。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "allow": [
    ],
  • "deny": [
    ],
  • "ask": [
    ]
}

重写项目的 permissions.json

一次替换全部三个列表。评估时 deny 仍优先于 allow——无法通过这里允许被拒绝的内容。

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
allow
required
数组:strings

自动批准的模式。

deny
required
数组:strings

禁止的模式。deny 优先于 allow,也优先于代理的自主权。

ask
required
数组:strings

始终需要人工决定的模式。

响应

请求示例

Content type
application/json
{
  • "allow": [
    ],
  • "deny": [
    ],
  • "ask": [
    ]
}

响应示例

Content type
application/json
{
  • "allow": [
    ],
  • "deny": [
    ],
  • "ask": [
    ]
}

列出自己在此项目中的 Personal Access Token

从不包含原始令牌——只包含已签发的信息。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

为本地 runner 签发一个 Personal Access Token

原始令牌(brb_...)只出现在这个响应中——之后无法找回,只保存哈希。用于 --token/BRABO_ACCOUNT_TOKEN(brabo-runner 的参数)。

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
name
required
string

供你以后认出这个令牌的名称——不要求唯一。

expiresInDays
number

N 天后过期。省略 = 不过期(随时可撤销,但绝不会自行过期)。

响应

请求示例

Content type
application/json
{
  • "name": "laptop",
  • "expiresInDays": 90
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000PAT000000000001",
  • "name": "laptop",
  • "projectId": "01JC4Z0000PROJETO000000001",
  • "createdAt": "2026-08-22T12:00:00.000Z",
  • "expiresAt": null,
  • "revokedAt": null,
  • "lastUsedAt": null,
  • "token": "brb_9f8a..."
}

撤销自己的 Personal Access Token

幂等——再次撤销不是错误。自 RN-685(ADR 0201)起,它还会断开用此令牌打开的 runner 连接,且只断开这些——同一用户的设备密钥不受影响——并作废其尚未使用的票据。engine 宕机不会导致撤销失败。

Authorizations:
bearer
path Parameters
projectId
required
string
tokenId
required
string

响应

撤销项目中任意用户的 Personal Access Token

事件响应——离职的开发者令牌泄露(RN-427)。幂等——再次撤销不是错误。自 RN-685(ADR 0201)起,它还会断开已用此令牌连接的 runner,且只断开它。

Authorizations:
bearer
path Parameters
projectId
required
string
tokenId
required
string

响应

列出项目中所有用户的全部 Personal Access Token

供 maintainer 用于事件响应的视图(RN-427)——包含每个令牌的所有者。从不包含原始令牌。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

列出自己在此项目中的设备密钥

没有人能撤销看不到的东西(RN-519)。包含已撤销的密钥——让记录消失会让界面声称该密钥从未存在。从不返回 JWK 公钥,私钥 api 从未见过。lastUsedAt 为空是孤立密钥的信号:已登记但从未被任何 runner 使用。自 RN-543 起,还包含调用方的机器密钥(especie: "maquina",projectId 为空),它们服务于此项目却不属于它——如果列表中没有它们,机器密钥在任何界面上都将不可见。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

撤销自己的一把设备密钥

幂等——再次撤销不是错误。自 RN-520 起还会断开活动连接:此前撤销只阻止新票据,已连接的 runner 会继续执行已批准的命令。自 RN-685(ADR 0201)起,目标是密钥本身:只断开用它打开的连接——如果是机器密钥则遍及所有项目——同一用户用 PAT 或其他密钥连接的另一个 runner 不受影响。它尚未使用的票据会被作废。engine 宕机或没有 runner 连接都不会导致撤销失败。

Authorizations:
bearer
path Parameters
projectId
required
string
deviceKeyId
required
string

响应

为本地 runner 连接签发一次性票据

用于 connect/3 认证,对象是 Phoenix 套接字 /runner(主题 terminal:<projectId>,角色 “runner”)——不是复用的 JWT,此路由本身只接受 Personal Access Token 代替会话 JWT(ADR 0105)。TTL 30 秒,一次性使用。如果项目不处于 “runner” 模式则以 400 拒绝(RN-421):在代码位于托管容器中的项目里,runner 无事可做。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "ticket": "string",
  • "expiresAt": "2026-08-09T12:00:30.000Z",
  • "engineWsUrl": "ws://localhost:4000/runner"
}

为 Web 的 Terminal 标签页签发一次性票据

同一个 /runner 套接字、同一个主题,角色为 “terminal”——即查看终端的一方(命令本身只有在有 runner 连接时才会真正运行)。适用于任何项目模式。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "ticket": "string",
  • "expiresAt": "2026-08-09T12:00:30.000Z",
  • "engineWsUrl": "ws://localhost:4000/runner"
}

列出此本地代理所服务的 “runner” 模式项目

通过机器设备密钥认证(ADR 0154)——绝不通过会话 JWT,也绝不通过绑定到项目的凭据,后者返回 403。返回处于 execution_mode: "runner" 的项目,其中密钥所有者至少拥有 developer(与 POST .../runner-ticket 的最低要求相同),并附带每个项目的文件夹名称和验证状态。代理会询问而不是扫描磁盘:机器的基目录属于用户,其中可能有并非任何项目的文件夹。

Authorizations:
bearer

响应

响应示例

Content type
application/json
[
  • {
    }
]

列出 workspace 中的每个项目及其容器(如有)

workspace 的每个项目一行——自 RN-521 起,从未置备过容器的项目会以 registrado: null 出现,而不是缺席,因为这个页面是人工启动第一个容器的途径。只对 provisioning/running 的行向 broker 查询观测状态,且仅在每次加载的预算之内——被跳过的行见 naoVerificado,原因见 ADR 0136。

Authorizations:
bearer
path Parameters
workspaceId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

操作

列出整个项目中跨任意会话的待处理操作

status 为 pending(默认)或 failed。actionType 按类型过滤——例如 git_merge,供 PR 标签页在不知道是哪个会话创建的情况下找到某个 PR 的合并提议。status=failed 要求提供 actionType,并列出执行失败的操作——PR 标签页从中读取每个 PR 最近一次被拒绝的合并(合并冲突会携带 executionResult.conflictingFiles)。

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
status
string
示例: status=pending
actionType
string
示例: actionType=git_merge

响应

响应示例

Content type
application/json
[
  • {
    }
]

列出授予每个代理的自主权

只有明确记录的规则。在此没有记录的代理会回落到项目 permissions.json 的默认值。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

为某个操作类型设置代理的自主权

按(代理,类型)upsert。它不会覆盖 permissions.json:已在 deny 中的模式无论在此授予多少自主权都保持阻止。actionType: "*" 即“自动模式”(RN-153)——对该代理任意操作类型的自主权;之后记录的特定规则在该类型上仍优先于通配符。

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
agentId
required
string

代理的 slug。

actionType
required
string
枚举: "terminal" "git_commit" "git_push" "pr_open" "spend" "git_repo_create" "git_branch_create" "git_branch_protect" "write_file" "open_adr_pr" "git_merge" "open_infra_pr" "instruction_patch" "parallelize" "raise_max_parallel" "propose_execution_plan" "assess_implementability" "container_start" "container_stop" "container_remove" "container_recreate" "container_start_via_runner" "qa_environment_start" "*"

操作类型,或 "*" 表示该代理的所有操作类型——即 ApprovalCard 的“自动模式”(RN-153)。特定规则始终优先于通配符:记录 terminal: deny 时,即使已开启 "*": auto_approve,仍会拒绝终端操作。

mode
required
string
枚举: "auto_approve" "require_approval" "deny"

该代理对此类型的自主权。不会覆盖 permissions.json:deny 中的模式无论代理有多少自主权都保持阻止。

响应

请求示例

Content type
application/json
{
  • "agentId": "dev-api",
  • "actionType": "terminal",
  • "mode": "auto_approve"
}

分页读取会话中提议的操作

按 seq 排序;将 nextCursor 用作 afterSeq。latest=true 改为获取尾部(最新的 limit 个操作,仍为升序)并忽略 afterSeq。status=pending 只保留等待决定的操作——配合 latest 时是最新的待处理操作,这样拥有 200 个以上操作的会话不会把新的待处理操作挤出窗口(RN-637)。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
query Parameters
afterSeq
string
示例: afterSeq=6
limit
string
示例: limit=50
latest
string
示例: latest=true

获取会话尾部;忽略 afterSeq。

status
string
示例: status=pending

只支持 pending。

响应

响应示例

Content type
application/json
{
  • "items": [
    ],
  • "nextCursor": 7
}

提议一个具有外部效果的操作

操作在创建时依据项目的 permissions.json 进行评估。响应中的 resolvedPolicy 说明策略的决定:auto_approve 出来时即可执行,require_approval 等待人工决定,deny 一出生即被拒绝。不存在不经过这里就执行的路径。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
actionType
required
string
枚举: "terminal" "git_commit" "git_push" "pr_open" "spend" "git_repo_create" "git_branch_create" "git_branch_protect" "write_file" "open_adr_pr" "git_merge" "open_infra_pr" "instruction_patch" "parallelize" "raise_max_parallel" "propose_execution_plan" "assess_implementability" "container_start" "container_stop" "container_remove" "container_recreate" "container_start_via_runner" "qa_environment_start"

操作类型。每种类型都有自己的最低角色:git_push、git_merge 和 git_branch_protect 需要 maintainer,其余需要 developer。

required
object

提议者。

required
object

操作参数,形态因 actionType 而异。

响应

请求示例

Content type
application/json
{
  • "actionType": "terminal",
  • "actor": {
    },
  • "payload": {
    }
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRC",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 7,
  • "actionType": "terminal",
  • "payload": {
    },
  • "status": "pending",
  • "resolvedPolicy": "require_approval",
  • "actor": {
    },
  • "decidedBy": null,
  • "decidedAt": null,
  • "rejectionReason": null,
  • "executionResult": null,
  • "createdAt": "2026-07-27T14:33:10.900Z",
  • "updatedAt": "2026-07-27T14:33:10.900Z"
}

批准该操作,仅此一次

只适用于此操作。决定连同决定者的 id 一起保存在事件日志中。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
actionId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRC",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 7,
  • "actionType": "terminal",
  • "payload": {
    },
  • "status": "pending",
  • "resolvedPolicy": "require_approval",
  • "actor": {
    },
  • "decidedBy": null,
  • "decidedAt": null,
  • "rejectionReason": null,
  • "executionResult": null,
  • "createdAt": "2026-07-27T14:33:10.900Z",
  • "updatedAt": "2026-07-27T14:33:10.900Z"
}

批准该操作并把模式记录到 permissions.json

除了放行此操作外,还会把相应的模式加入项目的 allow 列表——今后匹配的操作会以 auto_approved 出来而无需询问。已在 deny 中的模式保持阻止。批准和模式在同一事务中记录。点击已被批准的操作属于幂等成功(desfecho: ja_aprovada),仅在模式缺失时才记录它。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
actionId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRC",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 7,
  • "actionType": "terminal",
  • "payload": {
    },
  • "status": "pending",
  • "resolvedPolicy": "require_approval",
  • "actor": {
    },
  • "decidedBy": null,
  • "decidedAt": null,
  • "rejectionReason": null,
  • "executionResult": null,
  • "createdAt": "2026-07-27T14:33:10.900Z",
  • "updatedAt": "2026-07-27T14:33:10.900Z",
  • "desfecho": "aprovada",
  • "padraoGravado": true
}

拒绝该操作

如果提供了理由,它会与决定一起保存在事件日志中。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
actionId
required
string
Request Body schema: application/json
required
reason
string

与拒绝一起保存在事件日志中。可选,但建议填写。

响应

请求示例

Content type
application/json
{
  • "reason": "The command would delete the working directory."
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRC",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 7,
  • "actionType": "terminal",
  • "payload": {
    },
  • "status": "pending",
  • "resolvedPolicy": "require_approval",
  • "actor": {
    },
  • "decidedBy": null,
  • "decidedAt": null,
  • "rejectionReason": null,
  • "executionResult": null,
  • "createdAt": "2026-07-27T14:33:10.900Z",
  • "updatedAt": "2026-07-27T14:33:10.900Z"
}

执行

项目的代理区域,以及每个 lead 的上限

项目诞生时就带有三个区域(RN-094),因此即使还没有 module_map,列表也是完整的。激活执行所增加的是 dev 区域的成员,每个模块一个。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

设置(或清除)某个区域的花费上限

需要 maintainer,理由与并行度上限相同:这是与项目和会话预算并列的独立、叠加的检查(ADR 0110)——不是级联,也不替代二者中的任何一个。限额以美元传入,并在服务端转换为微美元,与 BudgetsController 的约定相同。null 清除上限。

Authorizations:
bearer
path Parameters
projectId
required
string
key
required
string
Request Body schema: application/json
required
limitUsd
required
object or null >= 0

区域的上限,以美元计——与项目/会话预算(BudgetsController)相同的美元输入、微美元输出约定。null 清除上限:区域恢复为无限制,这也是从未设置过上限的区域的默认值。

响应

请求示例

Content type
application/json
{
  • "limitUsd": 20
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "key": "dev",
  • "leadAgentId": "dev-lead",
  • "maxParallel": 2,
  • "budgetMicros": 20000000,
  • "spentMicros": 4300000,
  • "members": [
    ]
}

修改某个区域的并行度上限

需要 maintainer 而非 developer,理由与激活执行相同:提高上限就是决定产品在不询问的情况下可以花多少。适用于后续请求——已在等待你决定的内容会继续等待。

Authorizations:
bearer
path Parameters
projectId
required
string
key
required
string
Request Body schema: application/json
required
maxParallel
required
number >= 1

区域 lead 在会话中无需请求你授权即可拥有的代理数量。最小为 1——零不表示“无限制”,而是无效配置,把它当作无限制会让一个笔误变成不受限制的花费。

响应

请求示例

Content type
application/json
{
  • "maxParallel": 4
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "key": "dev",
  • "leadAgentId": "dev-lead",
  • "maxParallel": 2,
  • "budgetMicros": 20000000,
  • "spentMicros": 4300000,
  • "members": [
    ]
}

激活执行阶段并为每个模块启动一个 dev agent

需要 maintainer 而非 developer,因为 dev agent 的 git 操作在 IAM 评估中继承激活者的角色——以 developer 身份激活会让代理无法打开 PR。module_map 中的每个模块都会在隔离的 worktree 中获得一个代理。

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
taskBudgetMicros
number

每个任务的预算,以微美元计。省略时使用领域默认值(DEFAULT_TASK_BUDGET_MICROS)。

maxGateCorrections
number

在任务变为 blocked 之前,dev↔gate 往返的次数。正是它阻止代理在修正循环中耗尽预算。

devAgentImpl
string
枚举: "real" "noop"

noop 在不使用 LLM 的情况下启动 dev agent,用于在不花费 token 的情况下端到端地演练执行基础设施。省略时使用 real。

terminalAllowPatterns
数组:strings

在 permissions.json 中放行的模式,供 dev agent 运行测试套件。deny 仍优先于此处列出的任何内容。

originSessionId
string

“激活执行”点击所来自的聊天会话的 id——Dev Lead/PO 的创作式/咨询式会话,绝不是执行会话。省略时(旧版调用方,例如在没有会话上下文的 Overview 中激活)不关闭任何会话,与以前相同。提供时,会在最后关闭它——但仅当它没有待处理的 handoff/操作/回合时(RN-135),并且如果它就是执行会话本身则绝不关闭。

响应

请求示例

Content type
application/json
{
  • "taskBudgetMicros": 500000,
  • "maxGateCorrections": 3,
  • "devAgentImpl": "real",
  • "terminalAllowPatterns": [
    ],
  • "originSessionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

响应示例

Content type
application/json
{
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "modules": [
    ]
}

返回项目当前的执行会话,或什么也不返回

最近的 active 会话,且已携带 execution.activated——与 activate 决定是重新激活还是新建时使用的标准相同(RN-139)。没有执行在进行时为 null。它的存在让 Executors 标签页不再从项目最近的会话推断这个会话,那会随会话变化而变化,界面中毫无线索。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "status": "active",
  • "kind": "criativa",
  • "name": "Cart checkout",
  • "nextSeq": 42,
  • "createdAt": "2026-07-27T14:03:22.187Z",
  • "updatedAt": "2026-07-27T14:31:09.004Z",
  • "closedAt": null,
  • "terminationReason": null,
  • "traceParent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

重新启用被熔断器触发的 dev agent

重置连续阻塞任务计数器(RN-047),让代理重新尝试认领工作。这是离开 idle_tripped 的唯一方式——没有自动解除阻塞。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
agentId
required
string

响应

响应示例

Content type
application/json
{
  • "ok": true
}

为某个模块再请求一个 dev agent

受 dev 区域上限约束(RN-083):在上限之内,代理会立即在自己的 worktree 中启动;超过上限时,响应是一个 proposed_action,类型为 parallelize,等待你的决定,在你决定之前什么都不会启动。上限设为多少可在 Settings 中按 lead 配置。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
module
required
string

模块名称,与 module_map 中的一致。会为其启动一个专用的 dev agent,位于隔离的 worktree 中。

响应

请求示例

Content type
application/json
{
  • "module": "api"
}

响应示例

Content type
application/json
{
  • "estado": "aguardando_autorizacao",
  • "actionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "ativosNaSessao": 2,
  • "maxParallel": 2,
  • "motivo": "string"
}

解除被阻塞任务的阻塞

重置 gate 修正计数器,并把任务交还给代理。这是修正上限的人工逃生口——没有自动解除阻塞。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
taskId
required
string

响应

响应示例

Content type
application/json
{
  • "ok": true
}

Anamnesis

列出代理指令的各个版本

最新的在前,每个都已携带与上一版本的差异,由服务端计算。

Authorizations:
bearer
path Parameters
projectId
required
string
agent
required
string
示例: dev-api

响应

响应示例

Content type
application/json
[
  • {
    }
]

恢复代理指令的某个先前版本

历史不可变:恢复不会删除任何东西,而是以旧内容创建一个新版本。需要 maintainer,因为它会从此改变代理的行为——与补丁的校准相同。

Authorizations:
bearer
path Parameters
projectId
required
string
agent
required
string
示例: dev-api
version
required
string
示例: 2

要恢复的版本。

响应

响应示例

Content type
application/json
{
  • "agent": "dev-api",
  • "restoredFrom": 2,
  • "toVersion": 5,
  • "cacheInvalidated": true
}

立即运行 Anamnese,无需等待 tick

需要 maintainer,理由与 Psychologist 重新分析相同:它运行 ToolLoop 并花费真实预算。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "ok": true
}

按 id 返回项目事件,并解析其所属会话

与按会话查找事件的路由不同:这里不知道会话。正是这一点让画像的证据标签落在正确的事件上,因为 Anamnese 的窗口跨越多个会话。

Authorizations:
bearer
path Parameters
projectId
required
string
eventId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRB",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 41,
  • "type": "chat.message",
  • "actor": {
    },
  • "payload": {
    },
  • "createdAt": "2026-07-27T14:30:58.512Z"
}

列出项目中每个代理的指令历史

从在项目中拥有版本的代理出发,而不是从静态名单出发——正是这一点让按模块划分的 dev agent(dev-api)显示出来。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

返回熟练度画像

默认是用户自己的画像;团队汇总视图只对管理该项目的人开放。能力画像是关于这个人的数据,最不令人意外的默认是看到你自己的。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

删除自己的画像并记录选择退出

只能是调用方自己的画像,绝不是别人的。选择退出会一并记录,因为没有它,下一轮会重新推导一切,删除就只是装样子。它故意设为 viewer:画像覆盖所有成员,要求 developer 会让被画像的 viewer 无法删除自己的画像。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "deleted": 2,
  • "optedOut": true
}

重新启用对用户自己的画像

撤销选择退出。从下一轮起重新开始推导画像。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "optedOut": false
}

Backlog

返回当前的 module_map、ADR 以及待办项

当前映射是 version 最高的那个(历史不可变)。待办项是 story↔映射的交叉校验:没有模块的 story,或指向不存在模块的 story。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "moduleMap": {
    },
  • "adrs": [],
  • "pendencies": [
    ],
  • "c4Diagram": {
    }
}

返回 epic → story → task 树

嵌套且完整,一次调用即可。已归档的 story(RN-727)不会列出。backlog 由代理通过 /internal/* 路由写入。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

计算业务规则 → story 的覆盖情况

将项目的规则与 story 的 businessRuleIds 交叉比对。完全没有 story 的规则是一项发现——是 PO 的待办项,而不是错误。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "rules": [
    ],
  • "uncoveredCount": 2
}

列出基础设施 PR 以及每个 PR 所处的 gate 阶段

InfraAgent 的制品(Dockerfile、compose、CI)。它们经过与 dev PR 相同的 QA 和 SecOps gate,背后没有任务或 worktree。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

列出项目中代理的未决问题(RN-858)

状态来自事件日志:未决即存在 artifact.open_question 但没有 open_question.answered。最新的在前,上限 50 条并附 total。

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
status
string
默认值: "open"
枚举: "open" "answered" "all"

响应

响应示例

Content type
application/json
{
  • "itens": [
    ],
  • "total": 0
}

回答一个未决问题(RN-858)

只有问题所在会话的作者才能回答。写入一条 decision_record(参与者:该用户,附 questionId)和 open_question.answered,并尽力请求 engine 恢复每个受影响任务被暂停的 QA gate(RN-860)。

Authorizations:
bearer
path Parameters
projectId
required
string
questionId
required
string
Request Body schema: application/json
required
resposta
string

自由文本回答。发送这个或者 aceitarSugestao: true。

aceitarSugestao
boolean

接受代理的建议作为回答。

响应

请求示例

Content type
application/json
{
  • "resposta": "404 for a code that does not exist.",
  • "aceitarSugestao": true
}

响应示例

Content type
application/json
{
  • "questionId": "ffa0420e-f70b-4e5b-99a0-434bff860467",
  • "eventId": "string",
  • "sessionId": "string",
  • "pergunta": "string",
  • "sugestao": "string",
  • "afeta": {
    },
  • "autor": "criativo",
  • "criadaEm": "2019-08-24T14:15:22Z",
  • "status": "open",
  • "autorDaSessao": "string",
  • "resposta": {
    }
}

返回如何在你的机器上运行交付物

RN-852(ADR 0213):当前的 artifact.run_instructions,在 open_infra_pr 携带 run 执行时发出。由 Infra 代理声明,从未在读者的机器上验证。没有时为 null。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "command": "cp .env.example .env && docker compose up --build",
  • "urls": [],
  • "envExample": true,
  • "app": {
    },
  • "qa": { },
  • "version": 1,
  • "eventId": "01JC4Z0000EVENTORUNINSTRUC01",
  • "declaredAt": "2026-10-11T12:00:00.000Z"
}

归档一个草稿 story(RN-727)

该 story 离开 backlog、覆盖、提升队列、Dev Lead 的计划和认领——其任务也一样。不会删除任何内容:记录保留并带有 archivedAt,backlog.story_archived 记录由谁、为何以及哪些任务。仅限没有执行中任务的 draft story。

Authorizations:
bearer
path Parameters
projectId
required
string
storyId
required
string
Request Body schema: application/json
required
reason
string

可选;记录在 backlog.story_archived 中。

响应

请求示例

Content type
application/json
{
  • "reason": "Duplicate of \"Register a user\"."
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000HISTORIA000000001",
  • "epicId": "01JC4Z0000EPICO000000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "title": "Add item to cart",
  • "description": "As a buyer, I want to gather items before paying.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "businessRuleIds": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "moduleIds": [
    ],
  • "status": "ready",
  • "proposedReady": true,
  • "returnedReason": "DoD too generic — spell out the acceptance criteria.",
  • "returnedAt": "2026-08-02T14:00:00.000Z",
  • "archivedAt": null,
  • "archivedReason": null,
  • "createdAt": "2026-07-25T09:00:00.000Z",
  • "updatedAt": "2026-07-25T09:40:00.000Z"
}

将被拒绝的 story 退回给 PO,并附上理由

该 story 离开提议队列,理由会变成固定在 PO 会话中的一条消息——与把 gate 退回给 dev 的模式相同。如果该会话的 PO 已不在运行,退回仍会被记录:这是用户的决定,不依赖于有代理在听。

Authorizations:
bearer
path Parameters
projectId
required
string
storyId
required
string
Request Body schema: application/json
required
reason
required
string

理由是必需的:它会变成固定在 PO 会话中的消息,没有理由的退回等于交还了没有任何信息的工作。

响应

请求示例

Content type
application/json
{
  • "reason": "The acceptance criteria don't cover the payment refusal case."
}

响应示例

Content type
application/json
{
  • "ok": true
}

修正草稿 story 的标题(RN-727)

仅限 draft story,且没有执行中的任务(in_progress/in_review)。写入 backlog.story_updated,附带旧标题和新标题。所需角色与其他 backlog 写入操作(提升/退回)相同。

Authorizations:
bearer
path Parameters
projectId
required
string
storyId
required
string
Request Body schema: application/json
required
title
required
string

已去除首尾空白;1 到 200 个字符。

响应

请求示例

Content type
application/json
{
  • "title": "Register a user"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000HISTORIA000000001",
  • "epicId": "01JC4Z0000EPICO000000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "title": "Add item to cart",
  • "description": "As a buyer, I want to gather items before paying.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "businessRuleIds": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "moduleIds": [
    ],
  • "status": "ready",
  • "proposedReady": true,
  • "returnedReason": "DoD too generic — spell out the acceptance criteria.",
  • "returnedAt": "2026-08-02T14:00:00.000Z",
  • "archivedAt": null,
  • "archivedReason": null,
  • "createdAt": "2026-07-25T09:00:00.000Z",
  • "updatedAt": "2026-07-25T09:40:00.000Z"
}

将 PO 提议的 story 提升为 `ready`

manual 模式(自 Phase 12c 起为默认)交还给用户的人工步骤:在提升之前,该 story 的任何任务都不能被任何 dev agent 认领。提升会一次性放出这批任务,并唤醒该模块中空闲的代理(Phase 12b)。这一批不是全有或全无——未通过的会以 failed 返回并附上原因,通过的则被提升。

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
storyIds
required
数组:strings

要提升为 ready 的 story 的 id。单个即为一批 1 个。每个 story 独立校验和提升——失败的不会阻塞其他的。

响应

请求示例

Content type
application/json
{
  • "storyIds": [
    ]
}

响应示例

Content type
application/json
{
  • "promoted": [
    ],
  • "failed": [
    ]
}

Psychologist

列出 Psychologist 关于代理的假设

每条假设都引用支持它的事件(evidenceEventIds)——正是这一点让它可审计,而不是凭信任接受。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

接受一条假设

将 proposed → accepted。不是 proposed_action:Psychologist 是只读的,这里没有任何外部效果。

Authorizations:
bearer
path Parameters
projectId
required
string
hypothesisId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000HIPOTESE000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "analysisId": "01JC4Z0000ANALISE0000000001",
  • "agenteAlvo": "dev-api",
  • "observacao": "The agent reopened the same task three times.",
  • "hipotese": "The instructions don't say when to consider the task done.",
  • "sugestao": "Add an explicit definition-of-done criterion to the instruction.",
  • "confiancaPercent": 72,
  • "evidenceEventIds": [
    ],
  • "terminationAnalysis": {
    },
  • "status": "proposed",
  • "decidedBy": null,
  • "decidedAt": null,
  • "createdAt": "2026-07-26T18:00:00.000Z",
  • "updatedAt": "2026-07-26T18:00:00.000Z"
}

驳回一条假设

将 proposed → dismissed。理由与接受相同。

Authorizations:
bearer
path Parameters
projectId
required
string
hypothesisId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000HIPOTESE000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "analysisId": "01JC4Z0000ANALISE0000000001",
  • "agenteAlvo": "dev-api",
  • "observacao": "The agent reopened the same task three times.",
  • "hipotese": "The instructions don't say when to consider the task done.",
  • "sugestao": "Add an explicit definition-of-done criterion to the instruction.",
  • "confiancaPercent": 72,
  • "evidenceEventIds": [
    ],
  • "terminationAnalysis": {
    },
  • "status": "proposed",
  • "decidedBy": null,
  • "decidedAt": null,
  • "createdAt": "2026-07-26T18:00:00.000Z",
  • "updatedAt": "2026-07-26T18:00:00.000Z"
}

列出分析轮次及其层级和真实成本

costMicros 由该轮的 token_usage 求和而得。正是这一点让轻量与重量分诊之间的成本差异可见,而不仅仅是断言——两个层级使用的确实是不同的模型。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

报告 Psychologist 今天是否可以运行新的分析

只读——没有副作用。enabled: false 表示暂停是产品决定(不是缺陷):已有的分析和假设不受影响。

Authorizations:
bearer

响应

响应示例

Content type
application/json
{
  • "enabled": false
}

触发对会话的重新分析

需要 maintainer 而非 developer,因为它会再次运行 ToolLoop 并花费真实预算——不同于接受或驳回,后者只移动本地状态。之前的分析会被标记为已取代。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

响应

响应示例

Content type
application/json
{
  • "ok": true
}

RAG

索引覆盖率:已索引的文件/会话与真实总数对比

真实计数(从不估算):.md 文件(位于项目仓库的 docs/docs/adr 下)与其中有分块的数量对比,项目的会话数与其中有分块的数量对比。这三个范围不包含“N 分钟前”——没有按范围的索引时间戳列,猜测的数字会说谎(与 ADR 0042 对模型评级的规则相同)。local(RN-455)是唯一的例外:lastAttachedAt 是该范围上真实的 MAX(created_at),因为浏览器上传没有可供比较的仓库状态。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "docs": {
    },
  • "adr": {
    },
  • "session": {
    },
  • "local": {
    },
  • "chunksTotal": 0,
  • "chunksWithoutVector": 0
}

将某次搜索的一个命中评判为有用或无关(RN-480)

RAG 测量唯一的真实性信号:延迟和降级率说明搜索是否运行了,却从不说明它是否正确。角色与 search 相同——能读取结果的人就能评判它。对同一搜索的同一分块重新投票会覆盖你自己的投票,而不是新增一票(每个参与者唯一),因此该指标衡量的是准确性而不是热情。

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
searchId
required
string <uuid>

产生此命中的搜索所返回的 searchId——绝不由客户端编造。

chunkId
required
string <uuid>

被评判的分块。必须是那次搜索返回的命中之一,否则返回 400。

verdict
required
string
枚举: "util" "irrelevante"

两个值,而不是 1-5 分制:更细的刻度会招致每个投票者标尺不同,之后任何聚合都无法还原。

响应

请求示例

Content type
application/json
{
  • "searchId": "9b1a67f9-9477-48e5-8a6c-11b70245e1d9",
  • "chunkId": "90e1f3df-a8a1-438e-8dd5-10e45398d051",
  • "verdict": "util"
}

响应示例

Content type
application/json
{
  • "searchId": "9b1a67f9-9477-48e5-8a6c-11b70245e1d9",
  • "chunkId": "90e1f3df-a8a1-438e-8dd5-10e45398d051",
  • "verdict": "util",
  • "rank": 0
}

附加一个本地文件夹(浏览器上传)作为只读参考(RN-455,ADR 0113)

浏览器已读取的文本内容(<input webkitdirectory>),绝不是宿主机路径——这一区别正是 ADR 0113 的全部要点。local 范围的幂等完全重建:每次调用都会删除并根据本次发送的文件重新创建,因此重新上传就是重新同步的机制。超过文件数/总字节数上限时拒绝(400),而不是悄悄截断——这是用户在文件夹选择器前的一次性操作,不是后台扫描。单个过大或扩展名无法识别的文件只会被跳过,绝不会让整批失败。

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
folderName
required
string

在浏览器中选择的文件夹名称——显示在覆盖率面板中。

required
数组:objects (LocalFolderFileDto)

最多 500 个文件。精确的字节总和上限(RAG_LOCAL_TOTAL_BYTES_LIMIT)和逐文件的扩展名允许列表由用例而不是此 DTO 强制执行——由各自有效的字符串组成的数组加起来仍可能是过大的载荷。

响应

请求示例

Content type
application/json
{
  • "folderName": "brabo",
  • "files": [
    ]
}

响应示例

Content type
application/json
{
  • "folderName": "string",
  • "filesIndexed": 0,
  • "filesSkipped": 0,
  • "chunksCreated": 0,
  • "embedding": {
    }
}

重建项目的 docs/ADR/会话索引(幂等完全重建)

来自 Chat RAG 面板的“立即重建索引”。根据当前状态删除并重建三个可信范围(RN-219)的分块——推送/会话关闭时没有自动监视器(决定记录在 ADR 0079/0080 中)。在会话很多的项目上可能需要一段时间:它对每个会话运行一次索引,每次都可能批量调用嵌入提供商。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
{
  • "docs": {
    },
  • "sessions": {
    },
  • "embeddingAvailable": true,
  • "embeddingReason": "string"
}

在项目已索引的分块上进行混合搜索(向量 + 词法)

将余弦相似度(pgvector)与词法 ts_rank(tsvector)结合,二者来自独立的查询,通过加权求和合并并按阈值截断(ADR 0080)。当嵌入提供商没有响应、搜索只用词法信号运行时,vectorAvailable: false 会发出提示——它从不假装运行了完整的混合搜索。

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
query
required
string

2 到 500 个字符之间——与 Code 标签页搜索的规则相同。

scopes
数组:strings
项 枚举: "docs" "adr" "session" "local"

缺省时搜索全部四个范围(RN-219/454)。

limit
number

1 到 10——缺省时使用上限。

响应

请求示例

Content type
application/json
{
  • "query": "how does the PR gate work",
  • "scopes": [
    ],
  • "limit": 10
}

响应示例

Content type
application/json
{
  • "query": "string",
  • "searchId": "9b1a67f9-9477-48e5-8a6c-11b70245e1d9",
  • "hits": [
    ],
  • "vectorAvailable": true,
  • "vectorUnavailableReason": "string"
}

会话

列出项目的会话

每个条目都带有 technical:仅当会话由仓库置备打开时为 true(从 repo_bootstraps 关联)。

Authorizations:
bearer
path Parameters
projectId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

在项目中打开一个会话

会话以 created 状态诞生,是代理所做一切的容器:事件日志、提议的操作和 token 预算都挂在它上面。kind 是必需的并会被记录:consultiva(咨询式)只对话,criativa(创作式)产出内容,并且是唯一接受 execution.activated 的。

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
kind
required
string
枚举: "consultiva" "criativa"

会话的意图。consultiva(咨询式)只是对话;criativa(创作式)是产出的那种——它与 Creative 代理开启构思,并且是唯一会进入执行的。必需:没有它响应为 400,因为类型是开启者的选择并会被记录。

name
string <= 80 characters

友好名称,可选。不会取代 id 的井号标签——界面会把两者组合起来。空白视为缺省。

响应

请求示例

Content type
application/json
{
  • "kind": "criativa",
  • "name": "Cart checkout"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "status": "active",
  • "kind": "criativa",
  • "name": "Cart checkout",
  • "nextSeq": 42,
  • "createdAt": "2026-07-27T14:03:22.187Z",
  • "updatedAt": "2026-07-27T14:31:09.004Z",
  • "closedAt": null,
  • "terminationReason": null,
  • "traceParent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

按 id 返回会话

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "status": "active",
  • "kind": "criativa",
  • "name": "Cart checkout",
  • "nextSeq": 42,
  • "createdAt": "2026-07-27T14:03:22.187Z",
  • "updatedAt": "2026-07-27T14:31:09.004Z",
  • "closedAt": null,
  • "terminationReason": null,
  • "traceParent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

设置或清除会话的友好名称

名称是导航标签,不会取代 id 的井号标签——界面会把两者组合起来,没有名称时退化为只显示井号标签。null 或空白字符串会清除名称。无法修改 kind:它是创建时的意图,之后修改会把它变成状态。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
name
required
object or null <= 80 characters

新名称。null(或空白字符串)会清除名称,会话恢复为只用井号标签标识——这是撤销的路径,因此该字段接受 null,而不需要单独的删除路由。

响应

请求示例

Content type
application/json
{
  • "name": "Cart checkout"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "status": "active",
  • "kind": "criativa",
  • "name": "Cart checkout",
  • "nextSeq": 42,
  • "createdAt": "2026-07-27T14:03:22.187Z",
  • "updatedAt": "2026-07-27T14:31:09.004Z",
  • "closedAt": null,
  • "terminationReason": null,
  • "traceParent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

Resumes the turn an engine restart interrupted

Human gesture, with no cap: the automatic resume happens once at boot (ADR 0226) and this is the button for the rest. The reply is the ACCEPT (the turn goes up in the engine); progress arrives on the session channel. Requires developer.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
agent
required
string

响应

响应示例

Content type
application/json
{
  • "ok": true
}

为上下文面板统计整个会话

在整个会话日志上统计的业务规则、决策记录和每个代理的制品(界面读取的是 200 个事件的尾部),以及此会话和其已批准的 Dev Lead 计划所激活的执行会话中被 git_commit/git_push 触及的文件(RN-828)。自 RN-844 起,它还返回规则和决策的条目(各最新 50 条;总数仍在 regras/decisoes 中)以及这些会话中打开的 PR 的文件,读取自 PR 标签页所读的同一 diff,每次调用最多 20 个 PR;prsNaoLidas 说明有多少被略过或失败。只读;没有新表。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

响应

响应示例

Content type
application/json
{
  • "sessoesLidas": [
    ],
  • "regras": 11,
  • "decisoes": 6,
  • "itensDeRegras": [
    ],
  • "itensDeDecisoes": [
    ],
  • "artefatosPorAgente": [
    ],
  • "arquivosTocados": {
    }
}

分页读取会话的事件日志

日志不可变,按 seq 排序。常规分页是增量式的:把上一个响应的 nextCursor 作为 afterSeq 传入。latest=true 则相反——它获取尾部并忽略 afterSeq,供那些在末尾打开而不是从头重建整个会话的界面使用(ADR 0021)。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
query Parameters
afterSeq
string
示例: afterSeq=40

返回 seq 大于此值的事件。

limit
string
示例: limit=50
latest
string
示例: latest=true

获取日志尾部;忽略 afterSeq。

actionId
string
示例: actionId=01JC4Z0000ACAO00000000000001

只返回 payload.actionId 为此操作的事件——例如它的 proposed_action.created,其中携带操作记录不保存的策略 reason 和 scopeRoot(RN-614)。可与其他参数组合;页内的 seq 不再连续,因此按操作过滤的调用方不得据此推算省略的数量。空值返回 400。

响应

响应示例

Content type
application/json
{
  • "items": [
    ],
  • "nextCursor": 41
}

向会话日志追加一个事件

仅追加:seq 由服务器分配,日志中的任何内容之后都不会被更新或删除。按设计没有编辑端点。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
type
required
string

事件类型。完整清单见 docs/reference/events.md。

required
object (ActorDto)
required
object

自由形态,因 type 而异。

响应

请求示例

Content type
application/json
{
  • "type": "chat.message",
  • "actor": {
    },
  • "payload": {
    }
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRB",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 41,
  • "type": "chat.message",
  • "actor": {
    },
  • "payload": {
    },
  • "createdAt": "2026-07-27T14:30:58.512Z"
}

按 id 返回日志事件

它的存在是为了让 Psychologist 的假设证据无论落在哪一页、无论信息流的过滤条件如何,都能找到所引用的事件。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
eventId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRB",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 41,
  • "type": "chat.message",
  • "actor": {
    },
  • "payload": {
    },
  • "createdAt": "2026-07-27T14:30:58.512Z"
}

重新打开已关闭的会话,保留其所有内容

只有 closed/closed_abnormally 可以重新打开,并且只能回到 active——closing 绝不回退(ADR 0183)。会话保留其事件日志、制品、已回答的问题和 handoff;kind 不变。一个新事件 session.reopened 记录之前的 closedAt 和 terminationReason,记录中的这两列会被清空。携带 execution.activated 的会话会被拒绝(sessao_com_execucao):请打开新会话并在那里激活执行。没有时间限制。需要 developer(ADR 0184)。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "status": "active",
  • "kind": "criativa",
  • "name": "Cart checkout",
  • "nextSeq": 42,
  • "createdAt": "2026-07-27T14:03:22.187Z",
  • "updatedAt": "2026-07-27T14:31:09.004Z",
  • "closedAt": null,
  • "terminationReason": null,
  • "traceParent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

代理在此会话中回答你所使用的语言

为调用方解析,绝不为会话解析:会话覆盖 > 账户选择 > 检测并确认的 > 界面语言(RN-618)。返回胜出者、其来源以及链条的每一环——并且当你最近的消息指向另一种语言、界面应当就此询问时,返回 detectionQuestion(RN-624)。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

响应

响应示例

Content type
application/json
{
  • "language": "pt-BR",
  • "origin": "interface",
  • "sessionOverride": null,
  • "account": "automatico",
  • "detected": null,
  • "interfaceLocale": "pt-BR",
  • "detectionQuestion": "es"
}

固定(或释放)你在此会话中的回复语言

只针对调用方,只在此会话中(RN-618)——其他参与者和你的账户选择不受影响。null 恢复为从账户继承。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
language
required
string or null <= 35 characters

代理仅在此会话中回答你所使用的语言(RN-618)——其他参与者绝不受影响。服务器能识别的任何 BCP-47 代码,以规范形式存储。发送 null(或 automatico)——该键是必需的——以恢复为从你的账户继承。

响应

请求示例

Content type
application/json
{
  • "language": "en"
}

响应示例

Content type
application/json
{
  • "language": "pt-BR",
  • "origin": "interface",
  • "sessionOverride": null,
  • "account": "automatico",
  • "detected": null,
  • "interfaceLocale": "pt-BR",
  • "detectionQuestion": "es"
}

为会话套接字签发一个不透明的一次性票据

该票据用于 engine 上会话 Phoenix 套接字 session:<id> 的 connect/3 认证——不是复用的 JWT。TTL 30 秒,一次性使用:每次重连(包括自动重连)都会请求新票据。scope: "heartbeat" 需要 viewer 角色;scope: "terminal" 需要 developer,与终端操作的最低角色相同。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
scope
required
string
枚举: "heartbeat" "terminal"

heartbeat 需要 viewer 角色;terminal 需要 developer——与 MIN_ROLE_FOR_ACTION_TYPE.terminal 的最低角色相同。

响应

请求示例

Content type
application/json
{
  • "scope": "heartbeat"
}

响应示例

Content type
application/json
{
  • "ticket": "string",
  • "expiresAt": "2026-08-09T12:00:30.000Z"
}

将会话移动到另一个状态

状态转换由领域的状态机校验,而不是由客户端:created → active → closing → closed | closed_abnormally。无效的跳转返回 409。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
status
required
string
枚举: "created" "active" "closing" "closed" "closed_abnormally"

目标状态。状态机会以 409 拒绝无效的跳转——从 created 只能到 active,并且从终止状态无法返回。

响应

请求示例

Content type
application/json
{
  • "status": "closing"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "status": "active",
  • "kind": "criativa",
  • "name": "Cart checkout",
  • "nextSeq": 42,
  • "createdAt": "2026-07-27T14:03:22.187Z",
  • "updatedAt": "2026-07-27T14:31:09.004Z",
  • "closedAt": null,
  • "terminationReason": null,
  • "traceParent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

代理

取消活跃代理进行中的回合

输入框的“停止”按钮(RN-122):在 engine 中终止进行中的 LLM 调用,在流中途切断连接——这是真正节省 token,而不仅仅是在客户端停止渲染。幂等:没有进行中的回合时,请求被接受但没有效果。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
agent
required
string
示例: po

活跃代理的 slug。

响应

响应示例

Content type
application/json
{
  • "ok": true
}

向活跃代理发送消息

响应只是一个确认,并在接受时返回——在代理的回合结束之前(ADR 0163)。代理的回复通过会话的事件日志和通道到达——而不是通过这次调用。如果代理正处于回合中,消息不会被拒绝:它会进入代理的队列(entrega: "enfileirada"),在当前回合结束时与其他排队的消息在一个回合中一起被读取;等待期间可以取消(RN-673,ADR 0191)。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
agent
required
string
示例: po

读取该消息的对话式代理的 slug:criativo、po、arquiteto、dev-lead、ux-designer 或 staff。任何其他 slug——包括 infra——都会以 422 拒绝;绝不会投递给默认代理(RN-584)。

Request Body schema: application/json
required
text
required
string [ 1 .. 10000 ] characters

用户发给会话活跃代理的消息。

响应

请求示例

Content type
application/json
{
  • "text": "I want to allow discount coupons at checkout."
}

响应示例

Content type
application/json
{
  • "ok": true,
  • "mensagemId": "01JC4Z0000EVENTO000000000001",
  • "entrega": "enfileirada",
  • "posicao": 2
}

取消代理队列中一条正在等待的消息

在代理处于回合中时发送的消息会在队列中等待,并在回合结束时被读取(RN-673)。等待期间,发送者可以取消它:engine 将其从队列中移除并记录 chat.message_cancelled;它绝不会展示给模型。取消别人的消息返回 403。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
agent
required
string
示例: po

队列中持有该消息的代理的 slug。

messageId
required
string
示例: 01JC4Z0000EVENTO000000000001

chat.message 事件的 id(消息路由返回的 mensagemId)。

响应

响应示例

Content type
application/json
{
  • "ok": true
}

在会话中启动一个代理

只有 Criativo 可以通过直接命令启动。其他每个代理都需要一个指向它的已接受的 handoff——该规则位于领域中,而不在这里,试图绕过它会返回 409。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
agent
required
string
示例: criativo

代理的 slug。

响应

响应示例

Content type
application/json
{
  • "agent": "po",
  • "status": "active"
}

回答代理的一组结构化问题

记录 chat.structured_question_answered,并把答案作为普通消息重新发送给代理。一组问题只能回答一次。在接受时返回,在代理的回合结束之前(ADR 0163):回合继续在 engine 中运行,其叙述、结束和失败通过会话通道和事件日志到达(agent.status、agent.response、agent.error)——绝不通过这个响应。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
agent
required
string
示例: criativo

提出问题(并将读取答案)的代理的 slug。

questionSetId
required
string
示例: 01JC4Z0000EVENTO000000000001

已回答的 chat.structured_question 事件的 id。

Request Body schema: application/json
required
required
object

以问题 id 为键的回答——这个 id 就是 chat.structured_question 中传来的那个。

property name*
additional property
string

响应

请求示例

Content type
application/json
{
  • "answers": {
    }
}

响应示例

Content type
application/json
{
  • "ok": true
}

确认架构已就绪,并向 Infra 提议 handoff

专用端点,而不是复用属于 Criativo 的 readiness:它们是会话中两个不同的里程碑,混为一谈会让事件日志含糊不清。在接受时返回,在代理的回合结束之前(ADR 0163):回合继续在 engine 中运行,其叙述、结束和失败通过会话通道和事件日志到达(agent.status、agent.response、agent.error)——绝不通过这个响应。到 Dev Lead 的 handoff 仍在到 Infra 的之后:engine 会一直持有它,直到收尾回合结束。幂等(ADR 0182,RN-635):已有待处理提议或已在项目中活跃的目标不会被再次触发,两者都如此时不记录任何内容。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

响应

响应示例

Content type
application/json
{
  • "ok": true,
  • "desfecho": "confirmado",
  • "jaAtendidos": [
    ]
}

确认 Criativo 的业务需求已得到验证

记录 necessity.validated。要求 Criativo 已在此会话中整合出一份 product_brief(RN-406)——没有它会被拒绝:没有可验证的内容。自 ADR 0185(RN-657)起,“我准备好了——需求已验证”的点击(POST .../readiness)会自行记录此事件,Web 端不再调用此路由;保留它是为了那些就绪点击早于该 ADR 的会话。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

响应

响应示例

Content type
application/json
{
  • "ok": true
}

列出会话中代理之间的 handoff

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

手动向所选代理提议 handoff

以 offered 状态诞生,与代理自己的 offer_handoff 完全一样——唯一的区别是由谁决定。toAgent 必须在可寻址目录中(区域 lead 或没有区域的代理);子代理或未知 slug 会以 400 拒绝。每个(项目,目标)最多一个待处理提议:见 desfecho(ADR 0182,RN-635)。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
toAgent
required
string

目标代理的 slug。必须是 lead 或没有区域的代理——绝不能是子代理。

响应

请求示例

Content type
application/json
{
  • "toAgent": "staff"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000HANDOFF00000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "fromAgent": "criativo",
  • "toAgent": "po",
  • "artifactId": "01JC4Z0000ARTEFATO000000001",
  • "status": "offered",
  • "createdAt": "2026-07-24T10:00:00.000Z",
  • "updatedAt": "2026-07-24T10:05:00.000Z",
  • "desfecho": "criado"
}

接受 handoff 并激活目标代理

只做一件事:转换为 accepted 并启动目标代理。这是除 Criativo 之外每个代理的常规激活路径。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
handoffId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000HANDOFF00000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "fromAgent": "criativo",
  • "toAgent": "po",
  • "artifactId": "01JC4Z0000ARTEFATO000000001",
  • "status": "offered",
  • "createdAt": "2026-07-24T10:00:00.000Z",
  • "updatedAt": "2026-07-24T10:05:00.000Z"
}

确认与 Criativo 的探索会话已完成

这是触发 product_brief 和到 PO 的 handoff 的按钮。在事件日志中记录 readiness.confirmed。在接受时返回,在代理的回合结束之前(ADR 0163):回合继续在 engine 中运行,其叙述、结束和失败通过会话通道和事件日志到达(agent.status、agent.response、agent.error)——绝不通过这个响应。

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

响应

响应示例

Content type
application/json
{
  • "ok": true
}

凭据

Stores an LLM API key imported by the local runner

Authenticated by a MACHINE device key (never a session JWT, never a project-bound credential). Same envelope encryption as POST /users/me/credentials. 409 credencial_existente when the user already has this provider and substituir is not true. The key is never logged nor returned.

Authorizations:
bearer
Request Body schema: application/json
required
provider
required
string
枚举: "anthropic" "openai" "openrouter" "nvidia-nim" "together" "deepinfra" "bitdeer" "vultr" "9router" "opencode-zen"
apiKey
required
string <= 512 characters

The API key in plain text. Encrypted before touching the database; NEVER logged and NEVER returned.

origem
required
string <= 200 characters

Tool and path the key was read from. Audit log only; never a value.

substituir
boolean

Must be true to replace an existing credential of this provider.

响应

请求示例

Content type
application/json
{
  • "provider": "anthropic",
  • "apiKey": "string",
  • "origem": "codex: ~/.codex/auth.json",
  • "substituir": true
}

响应示例

Content type
application/json
{
  • "provider": "anthropic",
  • "substituida": true
}

列出当前用户自己的凭据

无需角色:凭据关乎调用者本人,而不是某个 workspace 或项目。在同一列表中涵盖 LLM 密钥和 git 令牌。

Authorizations:
bearer

响应

响应示例

Content type
application/json
[
  • {
    }
]

登记或替换某个提供商的 API 密钥

按(用户,提供商)upsert。密钥在接触数据库之前通过信封加密进行加密,响应只携带投影——绝不包含机密,即使是加密后的也不包含。

Authorizations:
bearer
Request Body schema: application/json
required
provider
required
string
枚举: "anthropic" "openai" "openrouter" "nvidia-nim" "together" "deepinfra" "bitdeer" "vultr" "9router" "opencode-zen"
apiKey
required
string <= 512 characters

明文密钥。它在接触数据库之前通过信封加密进行加密,绝不会出现在任何响应中——即使是加密后的也不会。512 个字符的上限是防止荒谬载荷的保护,而不是格式校验:密钥是否有效由提供商在 POST /users/me/credentials/{provider}/test 回答。

响应

请求示例

Content type
application/json
{
  • "provider": "anthropic",
  • "apiKey": "sk-ant-api03-…"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000CREDENCIAL00000001",
  • "provider": "anthropic",
  • "createdAt": "2026-07-10T10:00:00.000Z",
  • "updatedAt": "2026-07-10T10:00:00.000Z"
}

移除某个提供商的凭据

幂等:删除不存在的内容也返回 { ok: true }。

Authorizations:
bearer
path Parameters
provider
required
string
示例: anthropic

响应

响应示例

Content type
application/json
{
  • "ok": true
}

用提供商检查已存储的凭据

检查是一个显式操作,与登记分开(ADR 0050):api 解密机密、调用提供商,只返回裁决——密钥绝不会返回,哪怕是一部分。三种结果都返回 200,因为请求已被处理;refused 是一种结果,不是协议错误。当(用户,提供商)没有凭据时返回 404——那时没有可测试的东西。

Authorizations:
bearer
path Parameters
provider
required
string
示例: openrouter

响应

响应示例

Content type
application/json
{
  • "resultado": "recusado",
  • "motivo": "connection test failed for openrouter: openrouter responded 401"
}

登记一个 git 令牌(加密,不测试)

使用自己的路径,而不是 users/me/credentials,因为请求体不同(token,且提供商枚举为 github/gitlab)。令牌经过加密并在未事先验证的情况下存储(ADR 0050);如需验证,请调用 POST /users/me/credentials/{provider}/test。读取、移除和测试复用 users/me/credentials 路由——它们是同一张表。

Authorizations:
bearer
Request Body schema: application/json
required
provider
required
string
枚举: "github" "gitlab"
token
required
string <= 512 characters

个人访问令牌。在接触数据库之前通过信封加密进行加密,绝不返回,即使是加密后的也不返回。登记时不会测试令牌(ADR 0050)——如需验证,请使用 POST /users/me/credentials/{provider}/test。512 个字符的上限是防止荒谬载荷的保护,而不是格式校验。

响应

请求示例

Content type
application/json
{
  • "provider": "github",
  • "token": "ghp_…"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000CREDENCIAL00000001",
  • "provider": "anthropic",
  • "createdAt": "2026-07-10T10:00:00.000Z",
  • "updatedAt": "2026-07-10T10:00:00.000Z"
}

用户

列出已认证用户自己的机器设备密钥

账户级别,路径中没有项目(RN-611):一行命令安装会在任何项目存在之前创建机器密钥,而其他所有列表都是按项目的。只返回机器密钥(especie: "maquina",projectId: null),且只返回调用方的——项目密钥保留在其项目的列表中,任何人都看不到其他用户的密钥(RN-519)。已撤销的密钥也包含在内:登记新的机器密钥会撤销上一把(RN-552),而这个列表就是体现这一点的地方。lastUsedAt 是一次记录的使用,绝不是活动连接;为空表示该密钥从未被使用。

Authorizations:
bearer

响应

响应示例

Content type
application/json
[
  • {
    }
]

撤销已认证用户自己的一把机器设备密钥

幂等——再次撤销不是错误。与 DELETE /projects/{projectId}/runner-device-keys/{deviceKeyId} 是同一种撤销:它还会断开用此密钥打开的活动连接,遍及所有项目(RN-520/RN-543)。自 RN-685(ADR 0201)起,目标是密钥本身:同一用户用 PAT 或其他密钥连接的另一个 runner 不受影响。该密钥尚未使用的票据会被作废。还没有项目时,就没有可断开的连接。项目密钥、不存在的密钥和其他用户的密钥都返回同样的 404。

Authorizations:
bearer
path Parameters
deviceKeyId
required
string

响应

读取已认证用户的界面语言和代理回复语言

Authorizations:
bearer

响应

响应示例

Content type
application/json
{
  • "locale": "pt-BR",
  • "responseLanguage": "automatico",
  • "detectedLanguage": null,
  • "detectedLanguageConfirmedAt": "2019-08-24T14:15:22Z",
  • "effectiveResponseLanguage": {
    }
}

写入已认证用户的界面语言和/或代理回复语言

两个字段都是可选且相互独立的——发送其中一个绝不会影响另一个,两者都没有的请求体返回 400。locale(界面)仍限定在 pt-BR/en 列表中。responseLanguage(RN-618)为 automatico 或任何可识别的 BCP-47 代码,以规范形式存储;无法识别的代码返回 400,请求体中的任何内容都不会被写入。

Authorizations:
bearer
Request Body schema: application/json
required
locale
string
枚举: "pt-BR" "en" "ru" "zh-Hans"

界面语言。限定在列表中——不是自由形式的 BCP-47。

responseLanguage
string <= 35 characters

代理回答所用的语言(RN-618):automatico 或服务器能识别其语言的任何 BCP-47 代码——开放列表,与 locale 不同。以规范形式存储(pt-br 变为 pt-BR)。无法识别的代码返回 400 并指明规则。绝不改变 locale。

响应

请求示例

Content type
application/json
{
  • "locale": "en",
  • "responseLanguage": "es"
}

响应示例

Content type
application/json
{
  • "locale": "pt-BR",
  • "responseLanguage": "automatico",
  • "detectedLanguage": null,
  • "detectedLanguageConfirmedAt": "2019-08-24T14:15:22Z",
  • "effectiveResponseLanguage": {
    }
}

回答关于检测到的语言的问题

检测到的语言成为偏好的唯一途径(RN-624):仅凭检测绝不会改变任何东西。confirm 写入 detectedLanguage + detectedLanguageConfirmedAt;decline 记录拒绝,以免再次询问同一种语言。返回回答之后的偏好设置。

Authorizations:
bearer
Request Body schema: application/json
required
language
required
string <= 35 characters

问题所涉及的语言——即 detectionQuestion,来自 GET .../sessions/:sessionId/response-language。

answer
required
string
枚举: "confirm" "decline"

confirm 将其存储为你检测并确认的语言(之后只要你的账户设置为自动,就会用它回答你);当你的消息已不再指向它时返回 409 deteccao_mudou。decline 存储拒绝,此后绝不再询问这种语言(之后确认它会清除拒绝)。

响应

请求示例

Content type
application/json
{
  • "language": "es",
  • "answer": "confirm"
}

响应示例

Content type
application/json
{
  • "locale": "pt-BR",
  • "responseLanguage": "automatico",
  • "detectedLanguage": null,
  • "detectedLanguageConfirmedAt": "2019-08-24T14:15:22Z",
  • "effectiveResponseLanguage": {
    }
}

workspace

列出调用方的 workspace

已按关联关系过滤——没有全局列表。每个条目都携带调用方自己的角色。

Authorizations:
bearer

响应

响应示例

Content type
application/json
[
  • {
    }
]

创建一个 workspace

不需要任何角色:创建者成为 owner。这是尚不属于任何 workspace 的人的唯一入口。

Authorizations:
bearer
Request Body schema: application/json
required
name
required
string >= 2 characters
slug
required
string^[a-z0-9]+(-[a-z0-9]+)*$

kebab-case。在系统中唯一,并在 URL 中可见。

响应

请求示例

Content type
application/json
{
  • "name": "Acme Corp",
  • "slug": "acme-corp"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000WORKSPACE00000001",
  • "name": "Acme Corp",
  • "slug": "acme-corp",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "toolRouterEnabled": true,
  • "createdAt": "2026-07-20T09:12:00.000Z",
  • "updatedAt": "2026-07-20T09:12:00.000Z"
}

按 id 返回 workspace

Authorizations:
bearer
path Parameters
workspaceId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000WORKSPACE00000001",
  • "name": "Acme Corp",
  • "slug": "acme-corp",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "toolRouterEnabled": true,
  • "createdAt": "2026-07-20T09:12:00.000Z",
  • "updatedAt": "2026-07-20T09:12:00.000Z"
}

修改 workspace 的名称或 slug

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
name
string >= 2 characters
slug
string^[a-z0-9]+(-[a-z0-9]+)*$

kebab-case。在系统中唯一,并在 URL 中可见。

响应

请求示例

Content type
application/json
{
  • "name": "Acme Corp",
  • "slug": "acme-corp"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000WORKSPACE00000001",
  • "name": "Acme Corp",
  • "slug": "acme-corp",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "toolRouterEnabled": true,
  • "createdAt": "2026-07-20T09:12:00.000Z",
  • "updatedAt": "2026-07-20T09:12:00.000Z"
}

删除 workspace

需要 owner。会连同其项目、会话及其历史一起删除。

Authorizations:
bearer
path Parameters
workspaceId
required
string

响应

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000WORKSPACE00000001",
  • "name": "Acme Corp",
  • "slug": "acme-corp",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "toolRouterEnabled": true,
  • "createdAt": "2026-07-20T09:12:00.000Z",
  • "updatedAt": "2026-07-20T09:12:00.000Z"
}

列出 workspace 的成员

谁与该 workspace 关联,以及其 workspace 角色——除非项目记录覆盖它,每个项目都会继承这个角色。补充 GET projects/:projectId/members,后者只列出项目记录:仅通过 workspace 进入项目的人出现在这里而不是那里。只包含 id、姓名、邮箱和角色。

Authorizations:
bearer
path Parameters
workspaceId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

将用户关联到 workspace

只有 owner 可以改动成员名单。这里的角色会被该 workspace 的所有项目继承。这个角色是必要的但不是充分的:在这里修改你自己的角色会以 403 拒绝,两个方向都是,且在任何地方都无法启用。上面没有更高层级来兜底,因此自我降级将无法通过界面恢复。降级另一个 owner 仍然允许——这是撤销所有权的唯一方式。

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
userId
required
string <uuid>

要关联的用户 id。

role
required
string
枚举: "viewer" "developer" "maintainer" "owner"

此关联中的角色。在项目上,它在两个方向上都覆盖 workspace 角色——只要关联存在,有效角色就是这个,无论更高还是更低——并且有两种变动会以 403 拒绝:降级 workspace owner,以及修改你自己的角色(任一方向)。在 workspace 上它就是单纯的角色,只有上述第二条上限:你不能修改自己的角色。

响应

请求示例

Content type
application/json
{
  • "userId": "3f1b2c8e-5a4d-4b7e-9c10-2d6f8a1b4c33",
  • "role": "developer"
}

响应示例

Content type
application/json
{
  • "workspaceId": "01JC4Z0000WORKSPACE00000001",
  • "userId": "01JC4Z0000USUARIO0000000002",
  • "role": "maintainer",
  • "createdAt": "2026-07-22T08:00:00.000Z"
}

解除用户与 workspace 的关联

只有 owner 可以调用,与 upsert 相同。移除 workspace 记录,并在同一事务中移除该用户在此 workspace 每个项目中的记录(项目角色覆盖 workspace 角色,保留它们会让该用户留在那些项目中),以及该用户在这些项目中的项目设备密钥和个人访问令牌。之后会尽力断开该用户在每个项目中的活动 runner 连接。机器设备密钥和已打开的会话不受影响——由于角色解析为无,它们不再能触及此 workspace。

移除你自己会以 403 拒绝,且在任何地方都无法启用:上面没有更高层级来兜底。正是这一条款保护了最后一个 owner——只有 owner 可以调用此路由且没有人能移除自己,因此每次成功调用后至少还有调用方是 owner。移除另一个 owner 是允许的——这是撤销所有权的方式——但记录所有者(createdBy)除外,它会以 409 criador_do_workspace 拒绝,直到 PUT :workspaceId/owner-of-record 把它转给另一个所有者:代理花费的 LLM 密钥和花费报告都是他们的。幂等:没有 workspace 记录的目标仍会清除其在此 workspace 中的项目记录,并返回 204。

Authorizations:
bearer
path Parameters
workspaceId
required
string
userId
required
string

响应

转移 workspace 的记录所有者

记录所有者是 createdBy:代理花费的是谁的 LLM 凭据、代理操作使用的是谁的 git 凭据(RN-058),以及花费报告归谁所有(RN-060)。它不授予授权——授权由角色决定。目标必须已经是该 workspace 的 owner(否则返回 409 titular_precisa_ser_owner)。从提交那一刻起,代理回合会查找新记录所有者的凭据;如果他们没有该模型提供商的凭据,回合会以该提供商现有的“没有登记凭据”结果结束——此路由不会事先检查。任何 owner 都可以调用,包括为另一个所有者调用。转给当前的记录所有者是空操作。

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
userId
required
string <uuid>

将成为记录所有者的用户 id。必须已经是此 workspace 的 owner。

响应

请求示例

Content type
application/json
{
  • "userId": "3f1b2c8e-5a4d-4b7e-9c10-2d6f8a1b4c33"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000WORKSPACE00000001",
  • "name": "Acme Corp",
  • "slug": "acme-corp",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "toolRouterEnabled": true,
  • "createdAt": "2026-07-20T09:12:00.000Z",
  • "updatedAt": "2026-07-20T09:12:00.000Z"
}

列出项目基目录内某个文件夹的子文件夹

Mounted 模式的文件夹选择器,由 api 而不是 runner 提供(RN-504)。严格限定在 BRABO_PROJECTS_BASE 内(ADR 0141):path 是可选的,默认为基目录本身,任何在其之外的 path 都返回 400——这是格式错误的请求,而不是权限问题,因为没有任何角色能浏览基目录之外的内容。

刻意设限:只列目录,最多 500 个(在截断之前排序,并用 truncado 说明),绝不递归,排除以点开头的条目,符号链接只报告而绝不跟随。被略去的内容会被计数(arquivos、simbolicos),这样满是代码的文件夹绝不会看起来是空的。

没有配套的 POST:创建文件夹属于物化挂载 workspace 的过程,绝不属于选择器。

Authorizations:
bearer
query Parameters
path
string

要列出的绝对路径。省略即基目录本身。必须位于 BRABO_PROJECTS_BASE 内;..、. 和相对路径会被直接拒绝,而不是被解析。

响应

响应示例

Content type
application/json
{
  • "base": "/home/voce/brabo",
  • "path": "/home/voce/brabo/clientes",
  • "entries": [
    ],
  • "truncado": false,
  • "arquivos": 12,
  • "simbolicos": 1
}

列出 workspace 的项目

Authorizations:
bearer
path Parameters
workspaceId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

在 workspace 内创建项目

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
name
required
string >= 2 characters
slug
required
string^[a-z0-9]+(-[a-z0-9]+)*$

kebab-case。在 workspace 内唯一。

maxConsecutiveBlocked
number

熔断器(Phase 12b——RN-047):连续多少个任务以阻塞结束会让该模块的 dev agent 停在 idle_tripped。省略时使用领域默认值(DEFAULT_MAX_CONSECUTIVE_BLOCKED)。从下一次激活执行起生效——不影响已在运行的代理。

storyPromotion
string
枚举: "manual" "auto"

谁把 story 从 draft 提升为 ready(Phase 12c——RN-048)。auto(自 RN-659 起为新项目的默认值):完整的 story 一出生就是 ready,没有人工步骤。manual:PO 提议,由你在 Backlog 标签页中决定。更改默认值并没有改写任何已有项目。领域校验(DoD/DoR/RF/规则/模块)在两种模式下完全相同;模式只改变由谁触发。

executionMode
string
枚举: "container" "mounted" "runner"

此项目的命令在哪里执行(RN-169/RN-421——ADR 0072/0104)。container(默认):由产品管理、位于 PROJECT_WORKSPACES_ROOT 内的文件夹,即通常的行为。mounted:你自己的一个文件夹,在 workspacePath 中给出,位于安装范围的基目录 BRABO_PROJECTS_BASE 内(ADR 0141)——创建时只校验路径格式和该基目录,文件夹本身稍后在 Infra 启动容器时创建(RN-501,ADR 0142)。runner:你自己的一个不需要 bind-mount 的文件夹——创建时只校验路径格式,项目以“未验证”状态诞生;在你的机器上运行 brabo-runner --project <id> --dir <folder> 来确认它(RN-423)。

workspacePath
string

文件夹的绝对路径,当 executionMode 为 mounted 或 runner 时必需,为 container 时拒绝。在这两种模式中,现在都只校验格式——绝对路径、不含 ..、不是系统根目录、不是系统文件夹、不与 Brabo 检出目录重叠(RN-422/RN-423)。mounted 增加一条规则:它必须位于 BRABO_PROJECTS_BASE 内,那是你机器上 Brabo 容器唯一能看到的文件夹(ADR 0141)——没有配置基目录时,此安装不提供该模式,创建时会说明这一点。磁盘稍后才会被触及:在 runner 中由 runner 触及,在 mounted 中在 Infra 启动容器时触及(RN-501,ADR 0142)。

language
string <= 35 characters

项目的语言(RN-619)——共享制品和没有人类作者的回合使用它。服务器能识别的任何 BCP-47 代码,以规范形式存储;无法识别的返回 400。省略时,项目以其创建者的有效回复语言开始(RN-618:账户选择 > 已确认的检测 > 界面语言)。

响应

请求示例

Content type
application/json
{
  • "name": "Checkout",
  • "slug": "checkout",
  • "maxConsecutiveBlocked": 3,
  • "storyPromotion": "auto",
  • "executionMode": "container",
  • "workspacePath": "/home/you/projects/store",
  • "language": "pt-BR"
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000PROJETO0000000001",
  • "workspaceId": "01JC4Z0000WORKSPACE00000001",
  • "name": "Checkout",
  • "slug": "checkout",
  • "workspaceDirName": "checkout-3f2b1c8e",
  • "executionMode": "container",
  • "workspacePath": null,
  • "workspaceVerifiedAt": null,
  • "mirrorPath": null,
  • "language": "pt-BR",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "taskBudgetMicros": 500000,
  • "maxConsecutiveBlocked": 3,
  • "storyPromotion": "auto",
  • "createdAt": "2026-07-21T11:00:00.000Z",
  • "updatedAt": "2026-07-21T11:00:00.000Z"
}

Mounted 模式项目的基目录

运营者机器上 api 和 engine 容器都能看到的那个唯一文件夹,按身份挂载(ADR 0141)。null——一种正常状态,绝不是错误——表示此安装没有 BRABO_PROJECTS_BASE,因此项目向导完全不能提供 Mounted 模式。每个 workspace 的值都相同:它是安装配置,workspaceId 只用于限定授权范围。

brokerConfigurado 回答同一问题的另一半:container 和 mounted 只通过 broker 启动容器(ADR 0144),因此没有它时向导不会预选 Mounted,而是提供 Runner(ADR 0161,RN-573)。

Authorizations:
bearer

响应

响应示例

Content type
application/json
{
  • "projectsBase": "/home/voce/brabo",
  • "brokerConfigurado": false
}

每个项目的阻塞任务数

workspace 中每个有阻塞任务的项目一行——用一次查询为仪表盘侧边栏的状态点提供数据,而不是对 backlog 调用 N 次。

Authorizations:
bearer
path Parameters
workspaceId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

一次调用拿到仪表盘卡片渲染所需的一切

workspace 中每个项目一行,包含 git 提供商、置备状态、预算、最近活动、等待提升的 story,以及决定代理名单的事实(RN-090)。

与 projects-status 同样的思路,只是高了一层:卡片网格是一次 workspace 读取,而不是 N 次项目读取。之前的做法每张卡片要发起七个轮询查询,有 23 个项目时仅仪表盘就突破了 300 次/分钟的速率限制。

Authorizations:
bearer
path Parameters
workspaceId
required
string

响应

响应示例

Content type
application/json
[
  • {
    }
]

workspace 汇总摘要

项目数、本月花费过 token 的代理以及本月花费——为项目仪表盘的摘要行提供数据。

Authorizations:
bearer
path Parameters
workspaceId
required
string

响应

响应示例

Content type
application/json
{
  • "activeProjects": 4,
  • "agentCount": 6,
  • "spentMicros": 12500000
}

为 workspace 开启或关闭 Jev 工具路由

默认开启。开启且回合模型来自 OpenRouter 时,拥有两个或更多工具的代理步骤会先询问 Jev 哪个工具合适,聊天模型只会被提供该工具和上一个工具。Jev 从不批准或拒绝任何东西:需要批准的操作仍然需要批准。Jev 的任何失败都会回落到整个目录。关闭它会停止对 Jev 的所有调用,其成本也随之停止。

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
enabled
required
boolean

是否由 Jev 为代理的每一步选择工具。默认开启;仅当回合模型来自 OpenRouter 时才起作用。

响应

请求示例

Content type
application/json
{
  • "enabled": false
}

响应示例

Content type
application/json
{
  • "id": "01JC4Z0000WORKSPACE00000001",
  • "name": "Acme Corp",
  • "slug": "acme-corp",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "toolRouterEnabled": true,
  • "createdAt": "2026-07-20T09:12:00.000Z",
  • "updatedAt": "2026-07-20T09:12:00.000Z"
}

一次调用获取多个项目中的未读事件

铃铛的抽屉,面向整个 workspace(RN-091)。每个游标说明该项目已读到哪个 seq,响应携带每个项目最近会话中在此之后的内容。

之所以用 POST,是因为它是唯一带请求体的动词,而不是因为它改变状态。 服务器不知道每个读者停在哪里:“读到这里”是存储在浏览器中的每个项目一个 seq,并且(刻意地)没有标记为已读的端点。因此截止点需要随请求传递,而这样的对有几十个——放在查询字符串中会变成很长的 URL,代理会截断它,还会把用户的项目 id 写进访问日志。该路由是幂等的且没有副作用:它返回 200,绝不返回 201。

取代了抽屉打开时每个项目一次的请求——23 个项目要花 286 次/分钟,而限制是 300。

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
required
数组:objects (UnreadCursorDto) <= 200 items

每个要查询的项目一个游标。空列表返回空列表——“我什么都没要”不等于“全都给我”。来自其他 workspace 的项目会被静默忽略,因为游标来自调用方的本地存储,可能带有旧 workspace 的残留。

Array (<= 200 items)
projectId
required
string <uuid>
afterSeq
required
number >= 0

此浏览器在该项目中已看过的最后一个 seq。返回 seq 严格更大的事件。0 表示“什么都没看过”,会带来最近会话的开头。

响应

请求示例

Content type
application/json
{
  • "cursors": [
    ]
}

响应示例

Content type
application/json
[
  • {
    }
]