Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9025835
fix(setup): pin profile adapter_version to the discovered runtime ver…
xiaoland Aug 31, 2026
b85b5fa
fix(setup): create profile workspace and bootstrap provider home auth
xiaoland Aug 31, 2026
6813bb0
docs(setup): document issue activation contract (trusted mention vs a…
xiaoland Aug 31, 2026
ae0e6ef
fix(github): auto-refreshing installation token + mention resolution …
xiaoland Aug 31, 2026
1bcf830
fix(worktree): fetch via system git instead of libgit2
xiaoland Aug 31, 2026
3e38c6d
fix(worktree): add worktree via system git as well
xiaoland Aug 31, 2026
6dd2d42
docs(prd): publication discretion contract
xiaoland Sep 1, 2026
d74d6e2
docs(tdd): platform-neutral internal event model
xiaoland Sep 1, 2026
aff7ac5
docs(prd,tdd): Issue Agent worktree takeover
xiaoland Sep 1, 2026
a9ff28f
docs: behavior contract amendments from design review
xiaoland Sep 1, 2026
2644760
refactor(events): typed platform-neutral EventKind + activation gates
xiaoland Sep 1, 2026
45c3bee
feat(group): Issue Agent worktree takeover
xiaoland Sep 1, 2026
df58697
fix(group): fenced sessions request a context reset instead of wedging
xiaoland Sep 1, 2026
f6e8dd0
feat(group): Braid System Prompt v2 - publication discretion + persis…
xiaoland Sep 1, 2026
a7a1a4c
docs(changelog): 0.3.1 Added section for prompt v2 and issue worktrees
xiaoland Sep 1, 2026
968010a
feat(group): native unassignment retires the Issue Agent Group
xiaoland Sep 1, 2026
fa852d7
feat(config): instance-scoped source checkout with setup auto-clone
xiaoland Sep 1, 2026
bd0e45f
feat(config): [runtime] worktrees location override
xiaoland Sep 1, 2026
e12bc20
fix(ingress): smoke-round activation fixes
xiaoland Sep 1, 2026
c05e10d
fix(store,reconcile): close two reconcile-mode wedges found in smoke
xiaoland Sep 1, 2026
0ba759c
fix(group): reopen reactivation provisions a fresh worktree for pre-w…
xiaoland Sep 1, 2026
986276c
fix(store): close on a dormant group consumes instead of wedging
xiaoland Sep 1, 2026
6bf27e3
fix(store): reactivation replaces every stale session of the agent
xiaoland Sep 1, 2026
ed0b415
fix(store): fenced-unknown turns replay their inputs at-least-once
xiaoland Sep 1, 2026
ccc76b5
fix(group): resume fences in-flight turns before any compatibility ve…
xiaoland Sep 1, 2026
ba7dd32
docs(changelog): 0.3.1 Fixed section for smoke-round store/reconcile …
xiaoland Sep 1, 2026
6fcff39
chore(release): bump version to 0.3.1 for the acceptance candidate
xiaoland Sep 2, 2026
5b07667
test(suites): BRAID_TEST_WAIT_SECONDS knob for polling budgets
xiaoland Sep 2, 2026
94e6642
fix(github): drop page param from App hook deliveries listing
xiaoland Sep 2, 2026
8a6b5f7
fix(group): report provider unavailable while no live connection exists
xiaoland Sep 3, 2026
6a2a9a8
fix(config): uncatalogued profile model is not a config error
xiaoland Sep 3, 2026
de03e8e
refactor(prompt): inform volatility, stop prescribing agent workflow
xiaoland Sep 3, 2026
b40a7aa
test(suite40): settle window for the baseline marker assertion
xiaoland Sep 3, 2026
47543fc
test(suite40): count Agent comments by the App actor
xiaoland Sep 3, 2026
270372e
test(suite40): fix pipefail SIGPIPE kill and App-actor turn-mirror check
xiaoland Sep 3, 2026
877ca41
fix(telemetry): write logs to stderr so stdout carries CLI results
xiaoland Sep 3, 2026
1078d8a
fix(tunnel): DNS propagation grace before the first public probe
xiaoland Sep 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,106 @@
All notable changes to Braid are recorded here. The project follows Semantic
Versioning once release artifacts are published.

## [0.3.1] - unreleased

### Added

- `[runtime] worktrees` overrides where generation-scoped Agent worktrees are
provisioned (default `<state>/worktrees`). Only new generations use a
changed location; existing generations keep the paths recorded in SQLite.
- `braid setup` clones the configured repository into the instance source
checkout (`<instance>/source`): one clone per repository, shared by all
Profiles as the worktree provisioning source. `profile.workspace` is now
optional and defaults to this source checkout; `braid doctor` validates it
("Source checkout" check).
- Braid System Prompt v2: Publication Discretion (a delivered comment or
mention never obligates a public reply; silence is a valid outcome) and the
private persistent workspace (`.braid/` files in the generation worktree,
git-excluded, surviving provider session replacement).
- Issue Agent sessions run in a dedicated generation-scoped worktree
(`worktrees/issue-<number>/<profile>-g<generation>`) bound to the issue's
sole same-repository Development linked branch, or the repository default
branch when zero or several exist; resume, reopen-reactivation, and Context
resets all restore the worktree as the session cwd.

### Fixed

- Live smoke (0.3.1 candidate, reconcile-only mode): Issue Agent worktree
provisioning no longer fails on the PR-only worktree record guard;
opening-body mentions now activate (scanned alongside comment/review
bodies, promoted from noop to pending mention); reconcile no longer skips
close/reopen transitions whose body digest survived, nor wedges close
events on dormant groups; reopen reactivation provisions a fresh worktree
for pre-worktree (v0.3.0) generations, replaces every stale session of the
agent, and never wedges the event pending on unselectable generations;
fenced-unknown turns replay their wake inputs at-least-once after the
reset lands; restart resume fences crashed in-flight turns before any
compatibility verdict and logs the exact incompatibility reason.
- Black-box suite hardening: provider connection loss now surfaces
`provider: unavailable` in health until reconnect succeeds; App hook
deliveries listing no longer sends the rejected `page` key; an
uncatalogued Profile model is no longer a config error (the provider is
the authority on model support); the System Prompt requires publishing
through `braid gh` only, so Agent comments are always App-authored and
uncorrelated identities are not invited.

- `braid setup` pinned a hardcoded profile `adapter_version`, so config
validation rejected the generated config whenever the discovered runtime
version differed (e.g. codex-cli 0.151.0). The profile now pins the
discovered runtime version.
- Reopen reactivation was not idempotent: when a newer assignment generation
was already active (or the reopen was delivered twice), reactivation
selected a stale sleeping generation, hit the unique active-assignment
index, and error-looped every tick, permanently wedging the group scheduler.
Reactivation is now an ensure-style no-op when the group is already
materializing/active/finalizing.
- A trusted `@braid` mention on a closed Work Item activated a new assignment
generation. Activation (`assign`/`mention`) now applies only to open Work
Items; closed groups sleep until reopen, as the lifecycle contract states.

### Changed

- The event ledger now stores the typed, platform-neutral `EventKind`
(`assign`/`unassign`/`mention`/`wake`/`invalidate`/`lifecycle`/
`origin_echo`/`noop`) plus a semantic detail instead of ad-hoc
GitHub-shaped classification strings (schema v2). Producers map platform
deliveries at ingress; queue and group consumers branch on `EventKind`
only. Cross-surface invalidation folds into `invalidate` with
`detail='cross_surface'`; agent-origin echoes and ping/unknown deliveries
are evidence-only and consumed at ingest.
- `braid setup` now creates the Profile workspace directory it writes into
the config; previously a fresh setup left the workspace missing and the
first Agent turn materialization failed with the Assignment parked in
`blocked`.
- `braid setup` now bootstraps the instance-scoped Codex provider home:
it imports `~/.codex/auth.json` when present and otherwise prints explicit
`CODEX_HOME=... codex login` instructions. Previously `braid serve` ran
with the provider perpetually disconnected and no guidance.
- `braid doctor` gained a "Codex credentials" check for provider-home
authentication, so the gap is caught before serving.

### Added

- Setup output and the user manual now state the Issue activation contract:
a trusted `@braid` mention from a MAINTAIN/ADMIN actor. Native Issue
assignment is GitHub-side Agent App provisioning that ordinary
manifest-created Apps cannot obtain; Braid detects the mode at runtime.

- The GitHub installation client no longer pins the initial installation
token: it is built via octocrab's installation auth state, which caches and
auto-refreshes the token. Previously every API call began failing with 401
"Bad credentials" one hour after `serve` started (token expiry), silently
wedging mention resolution, reactions, and the write outbox until restart.
- Mention-authority resolution now backs off exponentially (2s to 60s) on
persistent GitHub errors instead of retrying every 250ms scheduler tick.

- PR worktree provisioning fetched through libgit2, which ignores the
operator's credential helpers and proxy configuration and failed on real
networks ("no TLS stream available"). The fetch now uses the configured
system `git` executable; libgit2 remains for local reference/worktree
operations.


## [0.3.0] - 2026-08-31

### Added
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "braid"
version = "0.3.0"
version = "0.3.1"
edition = "2024"
rust-version = "1.93"
description = "GitHub working memory for local coding agents"
Expand Down
11 changes: 7 additions & 4 deletions config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,11 @@ provider = "openai"
model = "gpt-5.6-sol"
reasoning = "high"
user_instructions = "Keep design discussion concise and maintain the Issue description as working memory."
workspace = "/absolute/path/to/issue-workspace"
# Optional. The source Git checkout of the configured repository, shared by
# all profiles as the worktree provisioning source (one repository = one
# source checkout). Defaults to <config_dir>/source. Agent sessions never edit
# it directly; they run in provisioned generation-scoped worktrees.
# workspace = "/absolute/path/to/repository-source-checkout"
github_actor_node_id = "MDQ6VXNlcjEyMzQ1"
status_surfaces = ["issue"]
github_context_soft_ratio = 0.80
Expand All @@ -105,9 +109,8 @@ provider = "openai"
model = "gpt-5.6-sol"
reasoning = "high"
user_instructions = "Implement from linked Issue working memory and keep GitHub comments brief."
# A clean source checkout for the configured repository. Braid fetches from its
# origin and provisions generation-scoped PR worktrees below runtime.root.
workspace = "/absolute/path/to/repository-source-checkout"
# workspace: see the issue profile above; omit it to share the default
# instance source checkout.
github_actor_node_id = "MDQ6VXNlcjEyMzQ1"
status_surfaces = ["pr"]
github_context_soft_ratio = 0.80
Expand Down
2 changes: 2 additions & 0 deletions docs/10-prd/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -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;沉默是合法结果。私有工作区(worktree 内的笔记、草稿、中间态文件)在同一 assignment 代际内跨 Provider Session 替换存续。 |
| 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 分支(Agent 可自行切换/创建分支)。worktree 内 `.braid/` 目录不参与 git 跟踪,是否使用由 Agent 自行决定。 |
| 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 的独占租约。 |
Expand Down
7 changes: 5 additions & 2 deletions docs/10-prd/objects.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
20 changes: 19 additions & 1 deletion docs/10-prd/publication.md
Original file line number Diff line number Diff line change
@@ -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, drafts, and scratch state as
files in its own worktree — its private, persistent workspace (the SVC task
packet idea). The worktree survives Provider Session replacement within the
same assignment generation, so a fresh session after a Context Reset picks up
where the previous one left off. Braid never publishes private working state.
GitHub receives only Human-relevant conclusions.

## Attribution and Writes

`braid gh` implements the write side needed to use
the stable Braid App identity and prepends an immutable attribution block:

```markdown
Expand Down
16 changes: 9 additions & 7 deletions docs/10-prd/workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
51 changes: 42 additions & 9 deletions docs/20-product-tdd/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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. |
Expand All @@ -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

`store` owns the typed, platform-neutral event contract `EventKind`
(`assign`, `unassign`, `mention`, `wake`, `invalidate`, `lifecycle`,
`origin_echo`, `noop`) next to the events ledger it persists. 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
Expand Down Expand Up @@ -209,14 +221,35 @@ 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-<number>/<profile>-g<generation>`. 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 the instance source Git
checkout of the configured repository (one repository = one source checkout,
defaulting to `<instance>/source`), 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 under the configurable
`[runtime] worktrees` directory (default `<state>/worktrees`; only new
generations use a changed location — SQLite records each worktree's actual
path):

- PR Agent Group: `runtime.root/worktrees/pr-<number>/<profile>-g<generation>`,
bound to the fetched PR head;
- Issue Agent Group: `runtime.root/worktrees/issue-<number>/<profile>-g<generation>`,
bound to the Issue's sole same-repository Development linked branch when
exactly one exists, otherwise to the repository default branch
(`refs/remotes/origin/<default>`). Several Development branches are not an
error: the worktree still starts on the default branch, and the Braid
System Prompt tells the Agent it may switch or create branches in its
worktree as the work requires (Context lists the Development branches).

Every worktree gets `.braid/` added to its `.git/info/exclude` at provision
time: that directory persists across Provider Session replacement within the
same assignment generation and stays out of `git status`, commits, and
GitHub. The System Prompt states these facts and nothing more — whether and
how the Agent uses the directory is its own choice.

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

Expand Down
6 changes: 6 additions & 0 deletions docs/20-product-tdd/app-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 state as files in its worktree,
which persists across Provider Session replacement within the same assignment
generation; GitHub receives only Human-relevant conclusions.

GitHub Context is not developer instructions. Immediately after start, Braid
calls stable `thread/inject_items` with one Responses-API user message:

Expand Down
Loading
Loading