@brokkai/brokk-town 0.6.4 → 0.7.0
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.
- package/README.md +90 -541
- 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
|
-
|
|
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
|
-
|
|
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
|
|
25
|
+
# Or install the native Town executable:
|
|
72
26
|
sh install.sh vX.Y.Z-town
|
|
73
27
|
```
|
|
74
28
|
|
|
75
|
-
Both installation paths
|
|
76
|
-
|
|
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.
|
|
82
|
-
|
|
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
|
-
|
|
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
|
-
|
|
166
|
-
|
|
46
|
+
make build
|
|
47
|
+
export PATH="$PWD/bin:$PATH"
|
|
167
48
|
```
|
|
168
49
|
|
|
169
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
277
|
-
#
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
-
|
|
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
|
-
|
|
311
|
-
#
|
|
312
|
-
|
|
73
|
+
bt --demo
|
|
74
|
+
# In another terminal:
|
|
75
|
+
bt web --demo
|
|
313
76
|
```
|
|
314
77
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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
|
-
|
|
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
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
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
|
-
|
|
552
|
-
|
|
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
|
-
|
|
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
|
-
|
|
562
|
-
|
|
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
|
-
|
|
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
|
-
|
|
578
|
-
|
|
132
|
+
The `bots/` directories are standalone projects with their own Go modules, CLI
|
|
133
|
+
commands, tests, documentation and packaging:
|
|
579
134
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
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
|
-
|
|
587
|
-
|
|
588
|
-
|
|
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.
|
|
2
|
+
"version": "0.7.0",
|
|
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.
|
|
29
|
-
"@brokkai/brokk-town-linux-arm64": "0.
|
|
30
|
-
"@brokkai/brokk-town-darwin-x64": "0.
|
|
31
|
-
"@brokkai/brokk-town-darwin-arm64": "0.
|
|
28
|
+
"@brokkai/brokk-town-linux-x64": "0.7.0",
|
|
29
|
+
"@brokkai/brokk-town-linux-arm64": "0.7.0",
|
|
30
|
+
"@brokkai/brokk-town-darwin-x64": "0.7.0",
|
|
31
|
+
"@brokkai/brokk-town-darwin-arm64": "0.7.0"
|
|
32
32
|
}
|
|
33
33
|
}
|