diff --git a/docs/10-prd/glossary.md b/docs/10-prd/glossary.md index 166b755..980c0d9 100644 --- a/docs/10-prd/glossary.md +++ b/docs/10-prd/glossary.md @@ -27,12 +27,14 @@ | Profile Tag | Agent Profile 声明适用面的 tag-like 类型,例如 `issue`、`pr`;同一 Profile 可同时拥有多个 tag,也可以只适用于 Issue。 | | Braid System Prompt | Braid 在创建 Provider Session 时注入的高优先级、版本化指令,包括 Braid/CLI 的存在、GitHub Working Memory 协议,以及按 Issue/PR surface 选择的角色与任务说明。它帮助 Agent 使用产品能力,而不是把 Braid 变成限制 Agent 的权限沙箱。 | | Effective Agent Instructions | Provider 实际收到的指令组合:Braid System Prompt 加 Profile User Instructions。GitHub Context 是带来源边界的不可信工作数据,Event Reference 是 user message,两者都不是系统指令。 | +| Publication Discretion | 收到评论、review 或提及从不构成公开发表的义务。Agent 自行决定什么内容 Human-relevant;沉默是合法结果。私有推理只存活在物理 Provider Session 内,Context Reset 后即被丢弃。 | | Issue Agent | 一个带 `issue` Profile Tag、运行在某个 Issue 上的 Agent 实例。 | | Issue Agent Group | 同一 Issue 上所有平行 Issue Agents;没有 primary/sub-agent,收到相同 Context 与 Event Reference batch。 | | Issue Group Turn | 同一 Context Revision 和 Event Reference batch 并行扇出给一个 Issue Agent Group 的一次 turn。 | | PR Agent | 一个带 `pr` Profile Tag、运行在某个 PR 上的 Agent 实例。v1 只有 Implementation Agent;未来可增加 reviewer、advisor 等角色。 | | PR Agent Group | 同一 PR 上的 Agent 集合。v1 恰好包含一个 Implementation Agent;架构保留未来增加非实现角色的路径。 | | Implementation Agent | PR Agent Group 中负责修改代码的 Agent。v1 每个 PR 恰好一个,并独占一个专用 worktree。 | +| Agent Worktree | Braid 为每个 Agent Group session 供给的按 assignment 代际隔离的专用 worktree,即 Agent 的实际 cwd。PR Agent 绑定 PR head;Issue Agent 绑定该 Issue 唯一的同仓 Development 链接分支(无则绑定默认 origin 分支,多个则视为歧义并阻塞物化)。 | | Implementation Request | Issue Agent 根据某条 Issue comment 发起的一次实现请求。该 GitHub comment ID 是 `braid pr ensure` 的幂等键;同一 comment 只得到一个 PR,不同 comment 可得到不同 PR。 | | PR Activation | 启动一个 PR Agent Group 的机械事实。产品上等价于把 PR 交给 Braid;具体 GitHub signal 由 adapter 提供,不能在未验证前假定为原生 PR assignee。 | | PR Agent Lease | 将一个 PR、一个专用 worktree 和一个 `pr`-capable Profile 原子绑定给唯一 Implementation Agent 的独占租约。 | diff --git a/docs/10-prd/objects.md b/docs/10-prd/objects.md index 92922d3..a404f3b 100644 --- a/docs/10-prd/objects.md +++ b/docs/10-prd/objects.md @@ -29,7 +29,10 @@ An Agent Profile is a versioned Braid configuration containing a provider, model, reasoning setting, Profile User Instructions, cwd/workspace policy, sandbox/approval settings, and optional tools, skills, MCP, or other provider-specific resources. Tags declare whether it can serve `issue`, `pr`, -or both. +or both. The Profile `workspace` names a clean source checkout, never the +Agent's cwd: every Agent Group session runs in a dedicated generation-scoped +Braid worktree (the Issue's sole Development branch when unambiguous, +otherwise the default branch; the PR head for a PR Agent). Braid adds its own versioned System Prompt when materializing a Provider Session. It explains GitHub Working Memory, Braid and `braid gh`, concise public @@ -41,7 +44,7 @@ sub-agent roles. MVP acceptance deliberately uses: - one active Issue Agent per Issue Agent Group; - one Implementation Agent per PR Agent Group; -- one dedicated worktree provisioned for that PR Implementation Agent. +- one dedicated generation-scoped worktree per Agent Group session. Multi-Agent fan-out is not rejected, but cross-peer ordering, semantic merge, arbitration, and convergence are outside the MVP correctness claim. diff --git a/docs/10-prd/publication.md b/docs/10-prd/publication.md index d748b57..9b070b3 100644 --- a/docs/10-prd/publication.md +++ b/docs/10-prd/publication.md @@ -1,7 +1,25 @@ ## Agent Publication and Identity Braid does not mirror turn activity or final responses. Coding Agents publish -short messages themselves. `braid gh` implements the write side needed to use +short messages themselves. + +## Publication Discretion + +A delivered comment, review, or mention never obligates a public reply. The +Agent alone decides what is Human-relevant; a silent turn that only reads, +thinks, or edits local files is a valid outcome. Event References report +changes; they are not commands. + +The Agent may keep private working reasoning inside its Provider Session and +publish conclusions when they are ready. Braid never publishes private +reasoning. Private reasoning lives only in the physical Provider Session: a +Context Reset replaces that session and discards it, so durable conclusions +must be published to GitHub (a comment, a description update, or a commit) +before they are needed again. + +## Attribution and Writes + +`braid gh` implements the write side needed to use the stable Braid App identity and prepends an immutable attribution block: ```markdown diff --git a/docs/10-prd/workflow.md b/docs/10-prd/workflow.md index 1b165d7..bf8b4ea 100644 --- a/docs/10-prd/workflow.md +++ b/docs/10-prd/workflow.md @@ -2,10 +2,11 @@ ### Discuss -Issue Activation creates the Issue session. A native assignment does not -invent a turn. On installations without the special Agent App assignment -capability, the first trusted visible `@braid` both activates the dormant Issue -and supplies the first Wake Event. Later Human comments, newly populated +Issue Activation creates the Issue session. A native assignment and the first +trusted visible `@braid` on a dormant Issue are the same internal `assign` +event; neither invents a turn by itself. On installations without the special +Agent App assignment capability, that first mention both activates the dormant +Issue and supplies the first Wake Event. Later Human comments, newly populated included metadata, and unfolded content are Wake Events. They accumulate until the Quiet Window expires or the count threshold is reached. The Issue Agent receives one current Context plus coalesced Event References and decides @@ -49,6 +50,7 @@ Context on the next materialization. Issue unassignment is debounced; once settled it retires the active Issue Agent Group. Closing an Issue, closing a PR, or merging a PR does not interrupt a current turn. It grants at most one Finalization Turn, then a closed Issue or -closed-unmerged PR sleeps and a merged PR retires. Reopen rematerializes Context -and starts one ordinary debounced turn. Duplicate deliveries never grant extra -finalization turns. +closed-unmerged PR sleeps and a merged PR retires. A mention on a closed Work +Item does not wake the sleeping group; Reopen is the designed re-entry. Reopen +rematerializes Context and starts one ordinary debounced turn. Duplicate +deliveries never grant extra finalization turns. diff --git a/docs/20-product-tdd/README.md b/docs/20-product-tdd/README.md index 9218b72..aeec7d2 100644 --- a/docs/20-product-tdd/README.md +++ b/docs/20-product-tdd/README.md @@ -107,7 +107,7 @@ crates. Modules are deep and align with authority boundaries: | `provider::session` | `ProviderAgentSession` adapter that maps `AgentSession` to `AgentProvider` primitives and translates provider notifications into `SessionEvent`s, deduplicating the provider's response-side and notification-side observation of the same fact. | | `session_manager` | In-process `SessionManager` keyed by provider thread id; start/resume/get. Ephemeral per connection epoch: it is rebuilt from the durable store on every (re)connect because sessions bind the epoch's provider handle. | | `provider` | Provider-neutral capability contract and Codex NDJSON implementation. | -| `worktree` | Validate a Profile source checkout, fetch the bound PR head, provision one generation-scoped worktree per Implementation Agent, and expose recovery diagnostics; no Git-operation sandbox. | +| `worktree` | Validate a Profile source checkout, resolve the bound ref (PR head, sole Development branch, or default origin branch), provision one generation-scoped worktree per Agent Group, and expose recovery diagnostics; no Git-operation sandbox. | | `writer` | `braid gh`, attribution, reaction/status desired state, and write-outbox convergence. | | `telemetry` | Trace/metric/log creation, payload events, sampling configuration, and OTLP export. | | `tunnel` | Wrangler Quick Tunnel supervision and webhook URL handoff. | @@ -119,6 +119,18 @@ Module dependencies point one way only: `runtime` → `group` → `queue`, and sit above the leaf modules (`store`, `context`, `github`, `config`, `provider`, `worktree`, `telemetry`) and no lower layer imports an upper one. +### Internal Event Model + +`protocol.rs` owns the typed, platform-neutral event contract `EventKind` +(`assign`, `unassign`, `mention`, `wake`, `invalidate`, `lifecycle`, +`origin_echo`, `noop`). A producer translates platform deliveries into +`EventKind` at ingress and records only the internal kind plus the per-platform +opaque Event Reference; `queue` and `group` consume `EventKind` exclusively +and never branch on platform event names or actions. This is the seam at +which a future non-GitHub platform plugs in: it adds a producer mapping, not +new consumer logic. The current GitHub mapping is owned by +[`github.md`](github.md). + ### State authority Every piece of state has exactly one authority; everything else is a @@ -209,14 +221,24 @@ newer than the binary. Compatible application rollback is declared per release; an incompatible schema rollback restores the pre-migration backup rather than running a down migration. -For a PR-capable Profile, `workspace` names a clean source Git checkout of the -configured repository, not the directory in which the Agent edits. Braid -fetches the PR head from that checkout and provisions the actual Agent cwd under -`runtime.root/worktrees/pr-/-g`. SQLite records the -resolved source, worktree, remote head, and local branch as operational facts. -The provider session is started and later resumed only against that worktree. -This provides isolation and recovery identity without turning Braid into a Git -policy engine. +For any Agent-serving Profile, `workspace` names a clean source Git checkout of +the configured repository, not the directory in which the Agent edits. Every +Agent Group session runs in a dedicated generation-scoped worktree that Braid +provisions from that checkout: + +- PR Agent Group: `runtime.root/worktrees/pr-/-g`, + bound to the fetched PR head; +- Issue Agent Group: `runtime.root/worktrees/issue-/-g`, + bound to the Issue's sole same-repository Development linked branch when + exactly one exists, otherwise to the repository default branch + (`refs/remotes/origin/`). Several Development branches are ambiguous + and block materialization with an operator diagnostic, mirroring `pr ensure` + disambiguation. + +SQLite records the resolved source, worktree, bound ref, and local branch as +operational facts. The provider session is started and later resumed only +against that worktree. This provides isolation and recovery identity without +turning Braid into a Git policy engine. ## Error and Concurrency Model diff --git a/docs/20-product-tdd/app-server.md b/docs/20-product-tdd/app-server.md index aee48e0..670abd1 100644 --- a/docs/20-product-tdd/app-server.md +++ b/docs/20-product-tdd/app-server.md @@ -59,6 +59,12 @@ string consisting of: 2. a clear delimiter; 3. Profile User Instructions. +The versioned Braid System Prompt must state Publication Discretion +explicitly: a delivered comment, review, or mention never obligates a public +reply; the Agent may keep private working reasoning inside the session and +publish conclusions when they are ready; private reasoning does not survive a +Context Reset, so durable conclusions belong on GitHub. + GitHub Context is not developer instructions. Immediately after start, Braid calls stable `thread/inject_items` with one Responses-API user message: diff --git a/docs/20-product-tdd/github.md b/docs/20-product-tdd/github.md index 74ee541..1942266 100644 --- a/docs/20-product-tdd/github.md +++ b/docs/20-product-tdd/github.md @@ -51,6 +51,26 @@ external activity. - Unknown event/action/union variants are durably recorded and trigger reconciliation. They are never serialized generically into Agent input. +### GitHub → EventKind Mapping + +The GitHub producer maps deliveries onto the platform-neutral `EventKind` +contract; consumers never see GitHub event names or actions: + +| GitHub delivery | Internal `EventKind` | +| --- | --- | +| `issues.assigned` / PR assignment to the App (canonical-reread confirmed) | `assign` | +| First Trusted Braid Mention on a dormant Work Item | `assign` (same internal event as native assignment) | +| `issues.unassigned` (canonical-reread confirmed) | `unassign` | +| Comment/review created, `pull_request.synchronize`, review requested; Trusted Braid Mention on an already-active Work Item | `mention` / `wake` | +| Body/description/comment edits or deletions, review dismissed, review thread resolved | `invalidate` | +| `closed` / `reopened` / `merged` | `lifecycle` | +| Correlated Braid App or Profile-actor writes | `origin_echo` (recorded, never wakes or invalidates the same Agent) | +| `ping`, unknown variants | `noop` (recorded as reconciliation evidence) | + +A Trusted Braid Mention on a Work Item whose group sleeps because the Work +Item is closed is a `mention`, not an `assign`: closed groups do not wake; +reopen is the designed re-entry. + Subscribe to: - `issues` and `issue_comment`; @@ -82,6 +102,10 @@ activation modes: `ActivationIntent` and preserves that same comment as an urgent Wake Event, so materialization is followed by the first turn. +Both modes converge on the same internal `assign` event; the activation paths +differ only in how the platform expresses the signal, never in consumer +behavior. + Native unassignment is likewise available only in the first mode and must be confirmed from canonical assignees before entering debounce. The fallback is not presented as a fabricated assignment. diff --git a/docs/20-product-tdd/lifecycle.md b/docs/20-product-tdd/lifecycle.md index 33a3d59..0a5b6d9 100644 --- a/docs/20-product-tdd/lifecycle.md +++ b/docs/20-product-tdd/lifecycle.md @@ -11,7 +11,7 @@ Each Work Item/Profile pair has an Assignment Generation and one state: | State | Meaning | | --- | --- | | `dormant` | No active Braid assignment/activation. | -| `materializing` | Profile, Context, worktree when applicable, and physical Provider Session are being created. | +| `materializing` | Profile, Context, the generation-scoped worktree, and physical Provider Session are being created. | | `idle` | Session exists and no turn or pending Wake batch exists. | | `debouncing` | Wake Events are accumulating against one quiet deadline/count. | | `running` | One provider turn is active. |