@brokkai/brokk-town 0.6.5 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +90 -541
  2. package/package.json +5 -5
package/README.md CHANGED
@@ -11,599 +11,148 @@ theme is a look, not a lever: it reads the same snapshot, keeps the theme and
11
11
  any race chosen for a base in that browser, and never changes what Town does or writes
12
12
  to GitHub.
13
13
 
14
- ## Build and run
14
+ - [Install or build](#install-or-build)
15
+ - [First run](#first-run)
16
+ - [Houses and work](#houses-and-work)
17
+ - [Operator reference](#operator-reference)
18
+ - [Independent bot projects](#independent-bot-projects)
19
+ - [Development](#development)
15
20
 
16
- ```sh
17
- make build
18
- ./bin/bt --demo
19
- # In another terminal:
20
- ./bin/bt web --demo
21
- ```
22
-
23
- Bare `bt` runs in the foreground and prints its browser URL. The URL carries the
24
- access key, so it is printed only to a terminal; redirected output and the
25
- background service's log point to `bt web` instead. Ctrl+C, SIGTERM or
26
- SIGHUP stops Town, its bots and their agent processes. Closing the browser does
27
- not stop the service. Demo mode is isolated and never invokes bots, agents or GitHub.
28
-
29
- ```sh
30
- bt -d # start in the background instead
31
- bt status # running or stopped, and which towns it serves
32
- bt web # print the running service's browser URL
33
- bt shutdown # stop Town and its bots
34
- ```
35
-
36
- Client commands require a running Town and never start one; `bt status` and
37
- `bt harnesses` also work while it is stopped. There is no login registration,
38
- automatic service replacement, terminal UI, version polling or in-app installer.
39
- Use `--state-dir` for an independent installation and `--listen` for a loopback
40
- address. Each command accepts only its own flags: `bt COMMAND --help` lists them.
41
-
42
- ## Independent bot projects
43
-
44
- The `bots/` directories are standalone projects with their own Go modules, CLI
45
- commands, tests, documentation and packaging:
46
-
47
- | Project | Command |
48
- |---|---|
49
- | bug-bot | bbb |
50
- | feature-bot | bfb |
51
- | issue-bot | bib |
52
- | review-bot | brv |
53
- | release-bot | brb |
54
- | repo-bot | brp |
55
- | simplifier-bot | bsb |
56
- | mayor-bot | bmb |
57
-
58
- Build any bot by running `go build ./cmd/<command>` inside its directory.
59
- Town never imports bot Go packages. Each module chooses its own released acp-go
60
- dependency. The only integration boundary is the local worker protocol.
61
-
62
- `bundle.json` records the exact bot versions supported by this Town build and
63
- original source commits. `make build` builds all nine executables into `bin/`.
64
- Town resolves its bots beside its own executable and verifies their versions.
65
- A standalone `go install` of only `bt` is not a complete Town installation.
66
-
67
- ## Installation and releases
21
+ ## Install or build
68
22
 
69
23
  ```sh
70
24
  npm install -g @brokkai/brokk-town
71
- # Or install a published complete native bundle:
25
+ # Or install the native Town executable:
72
26
  sh install.sh vX.Y.Z-town
73
27
  ```
74
28
 
75
- Both installation paths include Town and all eight supported bots. To install a
76
- new version, stop Town, install the complete package, and start Town again.
29
+ Both installation paths install Town only. Node.js/npm (including `npx`) must
30
+ be available on the Town service PATH. Town starts each bot through its separately
31
+ published npm package, resolving `@latest` when a worker starts and using that
32
+ exact version for its lifetime. Restart Town to pick up new bot releases.
33
+ To update Town itself, stop it, install the new package, and start it again.
77
34
  The shell installer requires Python 3 and keeps each complete installation in
78
35
  its own directory under `INSTALL_DIR/.brokk-town`, with `bt` pointing to it.
79
36
 
80
37
  Projects have independent versions and suffix release tags: `vX.Y.Z-town`,
81
- `vX.Y.Z-issue-bot`, and equivalent tags for the other bots. A Town release bundles
82
- the versions in its manifest without publishing unchanged standalone bots.
38
+ `vX.Y.Z-issue-bot`, and equivalent tags for the other bots. Bot releases retain
39
+ older versioned worker APIs, so a newer bot continues to serve the API an existing
40
+ Town uses.
83
41
  See [RELEASING.md](RELEASING.md) for workflows and publishing configuration.
84
42
 
85
- ## Connect repositories
86
-
87
- Authenticate `gh` and your chosen agent first. Start Town, then add a repository:
88
-
89
- ```sh
90
- bt
91
- # In another terminal:
92
- bt add --repo OWNER/REPO
93
- bt start --repo OWNER/REPO --role issue
94
- bt settings --max-workers 4
95
- ```
96
-
97
- Each configured town starts all eight bot processes immediately, including paused
98
- houses. Pausing controls work; it does not remove the process. Agents start only
99
- when jobs are dispatched. Repo Bot begins with read-only inventory; automation
100
- houses start paused. Existing concurrency limits and GitHub authority checks apply.
101
-
102
- Deleting a town stops its workers. Ending Town stops every worker. A lost parent
103
- pipe also stops workers after an unexpected Town exit. An interrupted write remains
104
- uncertain until repository reconciliation or an explicit retry establishes what
105
- happened; a restart never blindly repeats it.
106
-
107
- ## Town settings, requests, and deletion
108
-
109
- Visit a town and choose **Settings**, then use **Configure agent for** to select
110
- the bot and configure its agent, model, and reasoning effort independently. Bug,
111
- feature, issue, review, release, simplifier, and repo bots can each use a different profile. Bots
112
- without a profile inherit **Town defaults**. Choose **Use town defaults** and save
113
- to remove a bot's independent profile. Save each changed profile before closing
114
- Settings. Repo Bot inventories the repository without an agent, then uses its
115
- configured profile only when repairing a failing branch. Choose **Repo Bot** in
116
- the profile selector to configure that repair agent.
117
-
118
- **Simplifier decisions** selects `suggest` (the default) or `auto`. Suggest keeps
119
- the Mayor as decision maker and shows Simplifier Bot's advice on every pending
120
- arrival. Auto lets the bot's assessment route routine work without a separate
121
- Mayoral decision, including closing low-value complex issues.
122
-
123
- ### What each bot takes on
124
-
125
- Each house can be told what work to accept and how much of it to produce. Every
126
- setting here is one the bot already supports, and a house refuses a setting it
127
- cannot honour rather than accepting it and ignoring it:
128
-
129
- | Setting | Flag | Houses |
130
- | --- | --- | --- |
131
- | Required labels | `--labels` | bug, feature, issue, review, simplifier |
132
- | Excluded labels | `--exclude-labels` | issue, review |
133
- | One selected item | `--only` | issue (an issue number), review (a PR number) |
134
- | Discovery focus | `--focus` | bug, feature, review |
135
- | Per-run limit | `--limit` | bug/feature (issues filed), review (findings), simplifier (proposals), repo (repair attempts per revision), hall (bulletin items) |
136
- | Attempts per item | `--attempts` | bug, feature, issue, review, release |
137
- | Verification command | `--verify` | every house; overrides the town's `verify` |
138
- | Release cadence, preflight, required workflows and assets | `--release-*` | release |
139
-
140
- ```sh
141
- ./bin/bt settings --repo BrokkAi/my-project --role issue --labels agent-ready --exclude-labels needs-discussion
142
- ./bin/bt settings --repo BrokkAi/my-project --role issue --only 412
143
- ./bin/bt settings --repo BrokkAi/my-project --role bug --focus 'the storage layer' --limit 3
144
- ./bin/bt settings --repo BrokkAi/my-project --role review --verify '["make","review-check"]'
145
- ./bin/bt settings --repo BrokkAi/my-project --role release --release-quiet-seconds 900 --release-burst 10 --release-burst-window-seconds 3600 --release-triage on
146
- ./bin/bt settings --repo BrokkAi/my-project --role issue --clear-policy
147
- ```
148
-
149
- Config-file towns take the same settings under `bot_policies`, keyed by house;
150
- the example lists every supported field. A town that sets none behaves exactly
151
- as it did before these settings existed.
152
-
153
- Town applies the same filters to its own queue that it sends to the bot, so the
154
- queue you read is the queue the house will take from. Filtered work is not
155
- hidden: each house's inspector states its policy, counts the inventory it holds
156
- back, and marks each held item, so you can always see what your own filter
157
- excluded. A house whose bundled bot is too old to read a policy is refused the
158
- dispatch with the bot and version named, instead of running unfiltered.
159
-
160
- ### Agent budgets
161
-
162
- A town can bound how much automation it starts in a repeating accounting period:
43
+ To build from source, use the Go version declared in [go.mod](go.mod):
163
44
 
164
45
  ```sh
165
- ./bin/bt settings --repo BrokkAi/my-project --budget-period day --budget-attempts 40 --budget-agent-minutes 600
166
- ./bin/bt settings --repo BrokkAi/my-project --budget-period none
46
+ make build
47
+ export PATH="$PWD/bin:$PATH"
167
48
  ```
168
49
 
169
- The period is `day`, `week`, or `month` on your local clock, and at least one of
170
- `--budget-attempts` or `--budget-agent-minutes` is required. Config-file towns
171
- take the same settings as `"budget": {"period": "day", "max_attempts": 40,
172
- "max_agent_minutes": 600}`.
173
-
174
- Town charges the budget for every attempt that started an agent. A repository
175
- inventory reads GitHub without one and is never charged; a branch repair is.
176
- When a ceiling is reached, Town stops dispatching new agent work for that town
177
- and says so in Town Hall with the time the period resets. Work already running
178
- finishes normally, cancellation and saved work are untouched, and the repository
179
- inventory keeps running so uncertain writes can still be reconciled. Other towns
180
- are unaffected: a budget is per town, not per worker slot.
181
-
182
- **Town cannot cap token or dollar spend.** No bundled agent harness reports usage
183
- back through the worker protocol -- the acp-go runner hands a bot the agent's
184
- final text and nothing else -- so Town would be enforcing a limit against numbers
185
- it never receives. Attempts and agent minutes are what it measures, so those are
186
- what it enforces. Where usage or cost is missing, Town Hall prints "not
187
- reported"; it never shows absent telemetry as zero. Attempts whose elapsed time
188
- never arrived are counted and reported separately rather than billed as free.
189
-
190
- ### Quiet hours
191
-
192
- Quiet hours are weekly windows in which Town starts no new agent work and
193
- makes none of its own GitHub writes: no filing, repairing, reviewing, merging
194
- or releasing. Set a default for every town, give one town its own windows, or
195
- opt one town out:
50
+ This builds `bin/bt`. Bot source builds and releases are independent.
196
51
 
197
- ```sh
198
- # Service default: weeknights and weekends.
199
- ./bin/bt settings --quiet-hours "mon-fri 19:00-07:00; weekends 00:00-24:00"
200
- ./bin/bt settings --quiet-hours none # remove the service default
201
- # One town's own windows, none at all, or back to the service default.
202
- ./bin/bt settings --repo BrokkAi/my-project --quiet-hours "daily 12:00-13:00"
203
- ./bin/bt settings --repo BrokkAi/my-project --quiet-hours none
204
- ./bin/bt settings --repo BrokkAi/my-project --quiet-hours default
205
- ```
52
+ ## First run
206
53
 
207
- Each window is `DAYS HH:MM-HH:MM`, joined with `;`. Days are `mon` through
208
- `sun`, ranges such as `mon-fri` or `fri-mon`, or `daily`, `weekdays` and
209
- `weekends`, and name the day a window starts. An end at or before the start runs
210
- past midnight into the next day, and `24:00` ends a window at midnight.
211
- Overlapping windows count as one. A window with no day, an unknown day, a time
212
- that is not `HH:MM`, or the same start and end is refused with the reason. The
213
- browser edits the same schedules: the service default under Capacity, and a
214
- town's own in Town settings. Config files take `"quiet_hours": [{"days":
215
- ["mon"], "start": "19:00", "end": "07:00"}]` at the top level for the default
216
- and in a town entry for its own, where `[]` opts the town out.
217
-
218
- Windows are read on the local clock of the machine running Town, by the clock
219
- on the wall: a window holds through a daylight-saving change, an hour the clock
220
- skips is never quiet, and an hour it repeats is quiet both times.
221
-
222
- Inside a window, work already running finishes as it would after Pause, and
223
- the repository inventory keeps running so uncertain writes are still
224
- reconciled. Town leaves closing declined issues and retired pull requests and
225
- filing review follow-ups for the first inventory after the window. Issues you
226
- submit yourself are still posted. Houses stay awake: the browser shows them as
227
- *quiet* rather than paused, the town header reads "Quiet hours · until …",
228
- Town Hall explains the hold, and `bt status --json` carries the same `quiet_hours`
229
- state for each town. When the window ends, scheduling resumes on its own with
230
- each house's usual cadence; nothing missed is replayed. Pause and quiet hours
231
- are independent and both survive a restart: a paused house stays paused after
232
- the window, and a woken one resumes. Release Bot's own release quiet period
233
- (`--release-quiet-seconds`) is unrelated and keeps working as before.
234
-
235
- For each profile, select any agent from the
236
- [official ACP registry](https://agentclientprotocol.com/get-started/registry),
237
- plus **Anvil**, **Muse ACP**, **Draupnir**, or a custom ACP command. The full
238
- catalog loads from a bundled snapshot or local cache, then refreshes in the
239
- background when stale. **Refresh registry** checks for new agents and versions;
240
- failed refreshes preserve the last usable catalog. Demo stays offline.
241
-
242
- Selecting a registry agent saves its version and launch definition with that
243
- profile. Refreshing the catalog does not upgrade saved profiles. To upgrade, choose
244
- **Use registry version** in Settings, or pass the version shown by `bt harnesses`
245
- to `--harness-version`. Active work retains its starting settings.
246
-
247
- Town prepares the registry's distribution on first use: npm packages run through
248
- `npx --yes`, Python packages through `uvx`, and native archives download into
249
- Town's private cache. Install Node.js/npm or uv when the selected entry requires
250
- it. Native installs are shared across workers and check a checksum when the
251
- registry supplies one. Agents without a distribution for your platform are
252
- marked unavailable. Provider credentials and login remain the harness's own.
253
-
254
- The additional harnesses use the executable installed on the service's PATH:
255
-
256
- | Harness | Command | Setup |
257
- | --- | --- | --- |
258
- | [BrokkAi/anvil](https://github.com/BrokkAi/anvil) | `anvil` | `npm install -g @brokkai/anvil`; configure its model provider. |
259
- | [BrokkAi/muse-acp](https://github.com/BrokkAi/muse-acp) | `muse-acp` | Install the adapter and Muse Code; authenticate with `muse login`. |
260
- | [foundev/draupnir](https://github.com/foundev/draupnir) | `draupnir` | Install its release and configure its model provider. |
261
-
262
- These three use your installed versions. Their project links and setup notes
263
- also appear in Settings. A custom command supports other local ACP agents.
264
-
265
- **Load available choices** prepares and briefly starts the selected bot's harness
266
- without a work prompt, then lists its advertised models and reasoning efforts.
267
- Authenticate it in your terminal first. Choose a model before effort: available
268
- effort levels can depend on it. You can also enter an exact ACP selector value,
269
- or leave either field blank for the harness default. Unsupported selections fail
270
- visibly when the worker starts. Switching harnesses clears the previous harness's
271
- private authentication, command, and mode settings in the selected profile.
272
- Changing town defaults affects bots that inherit them; independent profiles keep
273
- their settings. Changes apply to the next worker run.
54
+ Authenticate `gh` and your chosen ACP agent, then start Town:
274
55
 
275
56
  ```sh
276
- ./bin/bt harnesses --refresh
277
- # Without --role, change the town defaults.
278
- ./bin/bt settings --repo BrokkAi/my-project --harness codex
279
- # Give each bot its own harness and exact selectors from available choices.
280
- ./bin/bt settings --repo BrokkAi/my-project --role review --harness claude --model MODEL_ID --effort EFFORT_ID
281
- ./bin/bt settings --repo BrokkAi/my-project --role issue --harness codex --model MODEL_ID --effort EFFORT_ID
282
- ./bin/bt settings --repo BrokkAi/my-project --role release --harness opencode --model MODEL_ID
283
- ./bin/bt settings --repo BrokkAi/my-project --role bug --harness BrokkAi/anvil
284
- ./bin/bt settings --repo BrokkAi/my-project --role feature --harness custom --agent-command '["my-agent", "--acp"]'
285
- # Blank selectors use this profile's harness defaults.
286
- ./bin/bt settings --repo BrokkAi/my-project --role review --model '' --effort ''
287
- # Remove the review profile and follow the town defaults again.
288
- ./bin/bt settings --repo BrokkAi/my-project --role review --inherit
57
+ bt
58
+ # In another terminal:
59
+ bt web
60
+ bt add --repo OWNER/REPO
61
+ bt start --repo OWNER/REPO --role issue
62
+ bt settings --max-workers 4
289
63
  ```
290
64
 
291
- `codex` and `claude` remain aliases for `codex-acp` and `claude-acp`.
292
- The model and effort IDs above are placeholders: use the exact values advertised
293
- by the selected harness. An effort such as `xhigh` is available only when that
294
- harness and model support it.
295
-
296
- For an OpenRouter-backed release bot, select **OpenCode** as its harness,
297
- authenticate OpenRouter in OpenCode with `/connect`, then load the release bot's
298
- available choices and select the desired OpenRouter model. OpenCode provides the
299
- ACP agent and OpenRouter supplies its model. See
300
- [OpenCode's OpenRouter setup](https://opencode.ai/docs/providers/#openrouter) and
301
- [ACP support](https://opencode.ai/docs/acp/).
65
+ Open the browser to configure the town's agent profiles and admit work. Repo Bot
66
+ starts enabled to read the repository; the other houses start paused. All eight
67
+ worker processes start when a town is added, but agents start only when jobs are
68
+ dispatched. Repo Bot's configured agent is used only for branch repairs.
302
69
 
303
- Choose **New request**, select **Feature request** or **Bug report**, and describe
304
- the work. **Create GitHub issue** posts it to that town's repository and places
305
- the confirmed issue in the workshop queue. This works while workers are paused;
306
- start issue-bot when you want implementation to begin. Recent submissions show
307
- the confirmation status and a link to the issue. Demo submissions stay local.
70
+ For an isolated demo that never invokes bots, agents or GitHub:
308
71
 
309
72
  ```sh
310
- ./bin/bt request --repo BrokkAi/my-project --kind feature --title 'Add keyboard navigation' --body-file request.md
311
- # Use --kind bug for a bug report; --body-file - reads stdin.
312
- ./bin/bt request --repo BrokkAi/my-project --check --request-id SAVED_ID
73
+ bt --demo
74
+ # In another terminal:
75
+ bt web --demo
313
76
  ```
314
77
 
315
- Requests have durable IDs, and the CLI prints the ID before sending. If the
316
- connection drops, reuse it with `--request-id` and the same content. The browser
317
- retains the submitted draft in that tab until acknowledgment. An uncertain GitHub
318
- POST is never automatically repeated: Town looks for its hidden receipt in all
319
- open and closed issues every five minutes. **Check GitHub for receipt** requests
320
- an earlier read. Inspect GitHub before manually filing an unconfirmed request again.
321
-
322
- To remove a town, choose **Settings → Delete town** and confirm, or run:
78
+ Bare `bt` runs in the foreground and prints its browser URL. The URL contains the
79
+ access key and is printed only to a terminal; use `bt web` when output is
80
+ redirected. Ctrl+C, SIGTERM or SIGHUP stops Town, its bots and their agents.
81
+ Closing the browser leaves the service running.
323
82
 
324
83
  ```sh
325
- ./bin/bt delete --repo BrokkAi/my-project
84
+ bt -d # start in the background
85
+ bt status # show whether Town is running and which towns it serves
86
+ bt shutdown # stop Town and its bots
326
87
  ```
327
88
 
328
- Deletion cancels its workers, cancels queued issue submissions, and removes it
329
- from the browser and terminal. GitHub repositories, issues, and PRs are preserved.
330
- Local history, uncertain writes, and private worktrees remain as recovery records.
331
- Adding the same repository again restores that history and its previous
332
- settings, with automation paused and the reporter enabled. A merge policy or
333
- harness/agent choice given with the add replaces the previous one; budgets, work
334
- policies, bot profiles, funnels and the branch are kept. A deleted town listed in
335
- `bt --config` is restored with the file's settings, and Town prints a notice. A town
336
- that already worked on one branch cannot be restored onto another. Deleting a
337
- town that is already deleted reports `unknown town`. Wait for stopping workers to
338
- finish before restoring a town.
89
+ Client commands require a running Town and never start one. `bt status` and
90
+ `bt harnesses` also work while it is stopped. Use `--state-dir` for separate state
91
+ and `--listen` for a loopback address. `bt COMMAND --help` lists a command's flags.
92
+ There is no login registration, terminal UI, automatic service replacement,
93
+ version polling, or in-app installer.
339
94
 
340
- ## How work moves
95
+ ## Houses and work
341
96
 
342
97
  | House | Work and handoff |
343
98
  | --- | --- |
344
99
  | Bug greenhouse | Runs bug-bot's investigation and verification; observed filed issues travel to issue-bot. |
345
100
  | Feature study | Runs feature-bot to discover useful new capabilities, independently review their value and feasibility, and compare existing requests; confirmed feature issues travel to issue-bot. |
346
101
  | Simplifier clarifier | Reviews every incoming issue/PR for disproportionate complexity or low value, advises the Mayor, and discovers removal/replacement proposals. |
347
- | Town Hall (Mayor Bot) | Runs mayor-bot to judge every arrival awaiting a Mayoral decision and to write the town bulletin: the feed of features gained and bugs fixed, written for users. Paused by default; decisions wait for you until it is started. |
102
+ | Town Hall (Mayor Bot) | Runs mayor-bot to judge every arrival awaiting a Mayoral decision and to write the town bulletin: the feed of features gained and bugs fixed, written for users. Also displays Repo Bot reports. Paused by default; decisions wait for you until it is started. |
348
103
  | Issue workshop | Runs issue-bot on eligible issues, opens implementation-ready PRs, and repairs Town-owned PR branches from review feedback. |
349
104
  | Review observatory | Runs review-bot, independently checks the full change and every retained finding, then returns fixes or waits for merge requirements. |
350
105
  | Release depot | Runs release-bot's batching and publishing policy. Confirmed merged/direct commits accumulate here; a published stable release ships only commits proven to be its ancestors. |
351
106
  | Repo watchtower | Polls GitHub, reconciles arrivals and revisions, summarizes new commit titles, reports queue growth and blocked work. |
352
- | Town hall | Stores periodic and event-triggered repo-bot reports. |
353
-
354
- The first complete inventory establishes existing work without a burst of arrival
355
- animations. Subsequent deliveries follow durable, sequenced state changes.
356
- Animation never initiates a GitHub write. Reconnecting does not replay previously
357
- seen deliveries. External PRs receive reviews but their branches are left to their
358
- authors; only locally recorded Town-created branches enter automatic repair.
359
-
360
- Every new issue and PR first waits at Simplifier Bot (including work filed by
361
- Bug Bot and Feature Bot and implementation PRs created by Issue Bot). In the
362
- default **suggest** mode, its bounded assessment is attached to the resulting
363
- durable Mayoral decision: **Admit** sends the work to Issue Bot or Review Bot;
364
- **Decline** keeps Town from acting on it. In **auto** mode, Simplifier Bot can
365
- admit routine work and decline low-value complex work itself; a declined issue is
366
- closed through Repo-bot, while a contributor's declined PR is ignored rather than
367
- closed. Town's own declined implementation PR, by either the Mayor or Simplifier
368
- Bot, is closed like one that failed its second review, and its issue starts over.
369
- Simplifier Bot's own marked proposals do not recursively pass through intake.
370
-
371
- **Mayor Bot** lives in Town Hall. Start it like any other house and it judges
372
- every arrival that waits for a Mayoral decision: one worker run per arrival,
373
- in a detached worktree at the exact revision, from the town's description of
374
- the item (with Simplifier Bot advice or the Town review attached) and the live
375
- GitHub source. It answers admit, decline, or, for a bot update, delay, with a
376
- reason kept on the task; decisions go through the same path as your own clicks
377
- and are recorded under the Mayor Bot name. A judgment that fails is retried
378
- twice, fifteen minutes apart, then left for you. The same house writes the
379
- **town bulletin**, shown in Town Hall under "What changed": after work merges,
380
- at most every `bulletin_seconds` (default 21600), it summarizes the merged pull
381
- requests for the people who use the software as features, fixes and
382
- improvements, each citing its pull requests.
383
-
384
- A review is bound to the exact base, head, PR description, and discussion snapshot. A suppressed
385
- duplicate comment is still a finding to check. Complete coverage, explicit
386
- resolution of every concern, and validation evidence are required for a clean
387
- result. New commits invalidate review readiness.
388
-
389
- Every pull request Town works on ends merged or closed, and nothing waits on a
390
- person to press retry. The first review sends every finding back to Issue Bot
391
- for one fix round. If the second review still finds work at or above the town's
392
- `review_close_severity` (default `P2`, so P1 and P2 close), Town closes the pull
393
- request, deletes its branch, leaves the findings on the issue, and queues the
394
- issue for a fresh attempt from the current branch. Findings below the threshold
395
- are filed as follow-up issues and the pull request merges. A revision gets at
396
- most two attempts at any step: a reviewer or repair failure earns one more
397
- attempt after a short delay, and a second failure retires the pull request the
398
- same way. A contributor's pull request is never closed by Town; it goes to the
399
- Mayor instead. Review Bot picks pull requests that have never been tried before
400
- ones that failed, so one bad pull request cannot hold the queue.
401
-
402
- The default merge policy is `bot`: auto-merge eligible Town-created PRs. `manual`
403
- leaves every merge to the operator; because the current Release Bot protocol cannot
404
- limit its authority to publish while forbidding its release-preparation PR merges,
405
- Town pauses Release Bot and rejects attempts to start or retry it under this policy.
406
- `all` also permits eligible external PRs. Town-managed merges require current clean Town evidence, GitHub mergeability, required checks
407
- and approvals. Town uses an expected-head squash merge, without admin bypass.
408
- Change this at any time under **Town Settings → External contributions**, or
409
- with `./bin/bt settings --repo BrokkAi/my-project --merge-policy manual`.
410
- Repositories that require a merge queue or prohibit squash merging need manual
411
- merges for now. GitHub is the final authority at write time.
412
-
413
- ## Configuration and recovery
414
-
415
- Copy [docs/config.example.json](docs/config.example.json), edit the repository,
416
- bot profiles, verification command, and policy, then run:
417
-
418
- ```sh
419
- ./bin/bt --config /path/to/towns.json
420
- ```
421
-
422
- Configuration is one JSON object: optional `max_workers` and `quiet_hours` for
423
- the whole service, and a `towns` array. Each town supplies `repo`, optional `branch` and
424
- `harness`, `agent`, optional `bot_agents`, optional `verify` argument vector,
425
- `merge_policy`, `simplifier_mode`, optional `review_close_severity` (`P1`, `P2`
426
- or `P3`, default `P2`), optional `budget`, optional `bot_policies`,
427
- `poll_seconds`, `report_seconds`, and `max_cycles`. The example
428
- lists all required values. A config-file entry gets no defaults for
429
- `merge_policy`, `poll_seconds`, `report_seconds`, or `max_cycles`: omitting any
430
- of them rejects the file. The defaults quoted below apply to towns added with
431
- `bt add` or the browser. When `--config` includes `max_workers`, that value
432
- overrides the persisted service setting in the same atomic state update; a
433
- config without it preserves the saved limit. Town
434
- uses the repository's default branch when omitted, and keeps following it: the
435
- observed default is recorded as repository state, so renaming it moves the town
436
- with it and never overwrites a branch you chose. An initialized town's branch
437
- cannot be changed in place. A town saved by an older Town has the branch observed
438
- at its first inventory pinned in its configuration; setting `"branch": ""`
439
- explicitly releases that pin so the town follows the repository default again,
440
- while omitting the field keeps whatever the town already uses. Omitted towns are retained when loading a config.
441
- Agent configuration uses acp-go's `command`, `environment`, `auth_method`, `mode`, `model`, and `effort` fields.
442
-
443
- The top-level `harness` and `agent` define town defaults. `bot_agents` maps any of
444
- `bug`, `feature`, `issue`, `review`, `release`, and `simplifier` to a complete profile containing
445
- its own `harness` and `agent`, with an optional saved `harness_definition`.
446
- An absent role follows the town defaults. A configured role is independent:
447
- blank model or effort uses its harness default, and omitted agent fields do not
448
- inherit private command, environment, or authentication values from the town.
449
- The example gives review-bot Claude Code, issue-bot Codex, and release-bot OpenCode;
450
- bug-bot and feature-bot inherit the town defaults. Select models and efforts after
451
- authenticating each harness. Verification and scheduling settings remain shared
452
- at town level.
453
-
454
- Repo-bot and issue/review scheduling use `poll_seconds` (default 60). Quiet reports
455
- use `report_seconds` (1800). Bug-bot, feature-bot, and simplifier-bot run at most every 30 minutes; mayor-bot
456
- writes a bulletin at most every `bulletin_seconds` (21600) and only after something merged; release-bot
457
- checks every five minutes and retains its own quiet window, minimum gap, and
458
- batching decisions. Each worker attempt, including the repo inventory, has a
459
- two-hour deadline, and each GitHub call Town makes itself, such as the merge
460
- gate's read, gives up after one minute. A pull request
461
- gets one fix round and two attempts per revision at any step; `max_cycles` is
462
- accepted for compatibility but no longer extends that.
463
-
464
- Feature-bot uses its own effective ACP harness, model, and effort, plus the town's
465
- optional verifier, with a private workspace and durable publication state.
466
- It proposes scoped features with user value, repository evidence and acceptance
467
- criteria. A separate review rejects duplicate, already implemented, rejected or
468
- uncertain proposals before filing. Its verifier receives `FEATURE_COMMIT` and
469
- `FEATURE_FINDING`; shared verification commands must support the selected bot's
470
- environment. New towns keep feature discovery paused until started.
471
-
472
- Town Hall's **Automation outcomes** report separates worker attempts, filed
473
- findings, submitted implementation PRs, repository-confirmed merges, repair
474
- rounds, blocked or abandoned work, and verified releases for a selectable
475
- period. A submitted PR is an artifact rather than an accepted fix. Operators
476
- can mark each filed finding useful or a false positive only by adding an
477
- explanation. Records retain task and revision provenance and show elapsed time,
478
- token usage, and cost as unknown when the worker does not provide them. The CSV
479
- export includes the repository on every row for comparisons across runs and
480
- towns.
481
-
482
- Private state defaults to `$XDG_STATE_HOME/brokk-town` or
483
- `~/.local/state/brokk-town`. `--state-dir` selects another directory; `--demo`
484
- appends `demo`. A single writer lock, atomic snapshots, per-role bot state, and
485
- private worktrees keep towns separate. Events, logs, and repo-bot reports have
486
- bounded recent histories; task, intent, and automation outcome history persists.
487
- A worker's own log lines and phase changes are committed in batches of at most a
488
- couple of seconds, because every commit rewrites and fsyncs the whole snapshot;
489
- the newest line and phase always win, and everything buffered is committed before
490
- a run's result is.
491
- Browser access uses a per-service
492
- local key in a URL fragment. `connection.json` and state snapshots are mode 0600.
493
- Private agent commands, environment, and authentication configuration are omitted
494
- from public configuration snapshots for both town defaults and bot profiles;
495
- each bot's effective harness, model, and effort are visible.
496
-
497
- ### Source funnels
498
-
499
- Optional `funnels` make issue intake source-neutral. Each named funnel declares a
500
- provider, validated location/filter, a local credential reference, explicit
501
- priority policy, overlap policy, and allowlisted lifecycle mappings. Credential
502
- references are resolved by adapters at request time; secret values never enter
503
- Town state, model prompts, events, logs, or public snapshots. Public state shows
504
- the safe funnel configuration and each normalized item's source identity, URL,
505
- revision, external state, eligibility, capabilities, priority policy, last sync,
506
- and typed outcome.
507
-
508
- GitHub funnels support query, `selected_issues`, and comma-separated
509
- `include_labels`/`exclude_labels`. Focused selections are read by issue identity
510
- instead of relying on search indexing. `working` and `blocked` mappings translate
511
- the normalized lifecycle into confirmed label changes. Slack is the second real
512
- adapter: it reads a configured channel through paginated Web API calls and maps
513
- configured lifecycle actions to reactions plus bounded thread replies. Slack
514
- tokens are obtained from a private resolver immediately before each request.
515
- Read-only funnels and empty per-transition mappings stay visibly unsupported.
516
-
517
- Funnels also recognize provider-native done signals on inbound reads. A Slack
518
- message with a present `:white_check_mark:` or `:heavy_check_mark:` reaction is
519
- normalized as **Done**; a GitHub issue whose state is `closed` is normalized as
520
- **Closed**. Both remain in the durable inventory with their source provenance,
521
- but become ineligible and leave the worker queue. A GitHub selector must include
522
- closed issues (for example `is:issue`, not `is:issue is:open`) if Town is to
523
- observe that transition. Done is based only on an explicit item state or reaction;
524
- an incomplete or empty inventory never closes missing work by implication.
525
-
526
- Lifecycle mutations use a durable intent before the provider call. A lost
527
- response remains `uncertain`; reconciliation is read-only and absence of a
528
- receipt never permits a duplicate label, reaction, comment, or thread reply.
529
- Incomplete reads, partial discovery, authentication failures, rate limits,
530
- unsupported actions, and uncertain writes remain distinct outcomes. Funnel
531
- declaration order is never scheduling priority. Overlapping source identities
532
- are retained, deduplicated, or rejected only according to the explicit overlap
533
- policy. Demo and tests use synthetic or fake providers and perform no live source
534
- or agent automation. See the complete JSON example for GitHub and Slack shapes.
535
- Local logs and worktrees can contain repository content; keep this directory private.
536
-
537
- If a push or merge response is lost, Town checks GitHub rather than assuming
538
- success. Inspect the task and its saved intent, then use **Reconcile and retry** or:
539
-
540
- ```sh
541
- ./bin/bt retry --repo BrokkAi/my-project --task pr:123
542
- ```
543
107
 
544
- Retry explicitly permits another attempt after fresh checks. For an uncertain
545
- repair push, it reuses and verifies the saved commit; it does not rerun the agent.
546
- If the PR moved, the saved worktree is retained for inspection. A retry also resets
547
- an exhausted repair budget. Never delete an uncertain intent to force progress.
548
- Retry clears that one task's block; it never starts a paused house. If the house
549
- is paused, the task says so and waits for you to start it.
108
+ The browser and CLI use the same committed state. Animation follows recorded
109
+ events and never writes to GitHub. Reviews require evidence tied to the exact
110
+ revision; zero new comments never proves a clean review. Interrupted writes stay
111
+ uncertain until reconciled.
550
112
 
551
- An uncertain repair is settled by ancestry, not only by an equal revision: once
552
- the commit Town pushed is proven to be in the pull request's history, the push
553
- landed, the intent is closed, and the newer revision goes back for review. Town
554
- never republishes the saved commit over work that built on it.
113
+ See [How work moves](docs/workflow.md) for intake, Mayor decisions, review and
114
+ repair limits, merge authority, release ancestry, and automation outcomes.
555
115
 
556
- A worktree is kept only while a saved intent still needs it. Repairs that fail
557
- before anything is pushed release their worktree and its `town-repair-*` branch
558
- immediately, and the issue house collects worktrees whose intent has since been
559
- confirmed, so an unattended town does not accumulate them.
116
+ ## Operator reference
560
117
 
561
- When the release house reports that Release Bot's retry budget is exhausted, fix
562
- the reported failure and ask Town to lift the budget:
118
+ - [Configuration](docs/configuration.md): every bot's agent profile, harnesses,
119
+ model choices, work policies, budgets, quiet hours, and config-file fields.
120
+ - [Requests and task controls](docs/operations.md): create work, snooze a task,
121
+ and delete or restore a town.
122
+ - [Recovery and saved work](docs/recovery.md): interrupted workers, uncertain
123
+ writes, setup diagnostics with `bt doctor`, merge blockers, and explicit task
124
+ or release retries.
125
+ - [Source funnels](docs/funnels.md): GitHub and Slack intake, credentials,
126
+ selectors, and source lifecycle guarantees.
127
+ - [Configuration example](docs/config.example.json).
128
+ - [Architecture](docs/ARCHITECTURE.md) and [worker protocol](docs/WORKER_PROTOCOL.md).
563
129
 
564
- ```sh
565
- ./bin/bt retry --repo BrokkAi/my-project --role release
566
- ```
567
-
568
- The next release run first calls the bot's `POST /v1/retry` worker API, which
569
- resets the pending release's attempt budget in its own workspace, then resumes
570
- the same release. Unlike a task retry, a release retry also starts the release
571
- house if it was paused. Town never edits the bot's private state. The pinned Release
572
- Bot must advertise the `retry` capability; older pins report that plainly.
573
- Use `bt status --json` to inspect saved details and GitHub to resolve conflicts.
574
-
575
- ### Snoozing one task
130
+ ## Independent bot projects
576
131
 
577
- To set one issue or pull request aside without pausing its house, snooze it
578
- until a chosen time. Open the task in the browser and choose **Snooze…**, or:
132
+ The `bots/` directories are standalone projects with their own Go modules, CLI
133
+ commands, tests, documentation and packaging:
579
134
 
580
- ```sh
581
- ./bin/bt defer --repo BrokkAi/my-project --task pr:123 --until 2d --reason "waiting on the vendor fix"
582
- ./bin/bt defer --repo BrokkAi/my-project --task issue:45 --until 2026-10-01T09:00:00Z
583
- ./bin/bt undefer --repo BrokkAi/my-project --task pr:123
584
- ```
135
+ | Project | Command |
136
+ |---|---|
137
+ | bug-bot | bbb |
138
+ | feature-bot | bfb |
139
+ | issue-bot | bib |
140
+ | review-bot | brv |
141
+ | release-bot | brb |
142
+ | repo-bot | brp |
143
+ | simplifier-bot | bsb |
144
+ | mayor-bot | bmb |
585
145
 
586
- `--until` takes an RFC 3339 time or a delay from now (`90m`, `4h`, `2d`); the
587
- resume time must be in the future and within 366 days, and the reason is one
588
- line of at most 200 characters. The house keeps working the rest of its queue.
589
- Until the resume time, no agent starts for the snoozed task: Issue, Review and
590
- Simplifier Bots skip it, Mayor Bot does not judge it, and Town does not merge
591
- it. A run already under way when you snooze finishes. The Mayor can still decide
592
- a snoozed arrival by hand.
593
-
594
- The task shows as **Snoozed** with its reason and resume time in the browser
595
- and in `bt status --json` (`deferred_until`, `defer_reason`). Snoozed is distinct from
596
- blocked and failed, so a snoozed task does not appear in the inbox. At the
597
- resume time Town clears the snooze, wakes the house and records the event; the
598
- snooze is saved state, so it survives a restart and repository reconciliation.
599
- Resume now (`bt undefer`) makes the task eligible immediately. Finished work
600
- (merged, closed, declined, or an implemented issue) cannot be snoozed.
601
-
602
- The HTTP listener accepts loopback IPs only (default `127.0.0.1:8099`). Host,
603
- origin, and bearer key checks protect the local API. A browser supporting WebMCP
604
- can list towns and navigate to a house through optional page tools. Unsupported
605
- browsers use the ordinary interface.
146
+ Build any bot by running `go build ./cmd/<command>` inside its directory.
147
+ Town never imports bot Go packages. Each module chooses its own released acp-go
148
+ dependency. The only integration boundary is the local worker protocol.
606
149
 
150
+ Town uses `npx --yes -- @brokkai/PROJECT@latest version` to resolve a bot, then
151
+ starts the exact reported version with `worker --socket PATH`. Protocol ranges,
152
+ required capabilities and the worker identity are checked before dispatch.
153
+ The running version is recorded with each job; a worker never updates mid-job.
154
+ Initial package preparation requires registry access. Bot binaries are held in
155
+ npm's cache, not installed beside `bt`.
607
156
 
608
157
  ## Development
609
158
 
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.6.5",
2
+ "version": "0.7.2",
3
3
  "license": "Apache-2.0",
4
4
  "repository": {
5
5
  "type": "git",
@@ -25,9 +25,9 @@
25
25
  "arm64"
26
26
  ],
27
27
  "optionalDependencies": {
28
- "@brokkai/brokk-town-linux-x64": "0.6.5",
29
- "@brokkai/brokk-town-linux-arm64": "0.6.5",
30
- "@brokkai/brokk-town-darwin-x64": "0.6.5",
31
- "@brokkai/brokk-town-darwin-arm64": "0.6.5"
28
+ "@brokkai/brokk-town-linux-x64": "0.7.2",
29
+ "@brokkai/brokk-town-linux-arm64": "0.7.2",
30
+ "@brokkai/brokk-town-darwin-x64": "0.7.2",
31
+ "@brokkai/brokk-town-darwin-arm64": "0.7.2"
32
32
  }
33
33
  }