hivecode-mcp 0.14.1 → 0.14.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.
- package/HIVE_RULES.md +98 -98
- package/LICENSE +21 -21
- package/README.md +421 -421
- package/core.js +91 -91
- package/docs/ALWAYS_ON.md +310 -310
- package/docs/GITHUB_WORKFLOW.md +394 -394
- package/docs/HIVE_RULES.md +41 -41
- package/docs/MCP.md +157 -157
- package/docs/QUICKSTART.md +266 -266
- package/docs/SELF_HOSTING.md +256 -256
- package/docs/SLACK_SETUP.md +474 -474
- package/docs/TROUBLESHOOTING.md +105 -105
- package/hive-activity.js +336 -336
- package/hive-authors.js +46 -44
- package/hive-await.js +230 -230
- package/hive-branch.js +608 -607
- package/hive-busy.js +88 -88
- package/hive-coord.js +110 -110
- package/hive-gate.js +135 -135
- package/hive-github.js +3 -1
- package/hive-hook-install.js +179 -179
- package/hive-instructions.js +74 -74
- package/hive-land.js +695 -691
- package/hive-listen.js +81 -81
- package/hive-mailbox.js +520 -520
- package/hive-mcp-http.js +591 -591
- package/hive-mcp.js +33 -6
- package/hive-mux-proto.js +58 -58
- package/hive-mux.js +351 -351
- package/hive-notify.js +234 -233
- package/hive-obligations.js +247 -247
- package/hive-poll-proto.js +50 -50
- package/hive-pr-staleness.js +189 -189
- package/hive-pr.js +600 -512
- package/hive-privacy.js +327 -327
- package/hive-receipts.js +233 -233
- package/hive-relay-health.js +234 -234
- package/hive-repos.js +430 -430
- package/hive-room-key.js +210 -210
- package/hive-room-mode.js +1668 -1668
- package/hive-room-watcher.js +562 -561
- package/hive-secrets.js +89 -89
- package/hive-session.js +114 -114
- package/hive-setup.js +560 -560
- package/hive-slack-agent.js +408 -408
- package/hive-slack.js +2384 -2367
- package/hive-stdio.js +172 -172
- package/hive-stop-hook.js +293 -293
- package/hive-throttle.js +118 -118
- package/hive-time.js +71 -71
- package/hive-transport.js +578 -578
- package/hive-update.js +58 -58
- package/hive-version.js +110 -110
- package/hive-webhook.js +55 -54
- package/icr-merge.js +58 -58
- package/icr.js +851 -851
- package/lang-brace.js +305 -305
- package/lang-js.js +651 -651
- package/lang-json.js +211 -211
- package/lang-python.js +588 -588
- package/lang-ruby.js +230 -230
- package/lang-toml.js +136 -136
- package/lang-yaml.js +183 -183
- package/limits.js +413 -413
- package/package.json +1 -1
- package/reconcile.cjs +621 -621
- package/slack-app-manifest-agent.json +61 -61
- package/slack-app-manifest-inbound.json +36 -36
- package/slack-app-manifest.json +27 -27
- package/substrate.js +252 -252
- package/sync.js +169 -11
- package/token.js +201 -201
package/docs/GITHUB_WORKFLOW.md
CHANGED
|
@@ -1,394 +1,394 @@
|
|
|
1
|
-
# GitHub workflow: label an issue, get back a tested PR
|
|
2
|
-
|
|
3
|
-
Status, 13 Oct 2026:
|
|
4
|
-
- **Built:** the watcher (`hive-github.js`).
|
|
5
|
-
- **Tested:** `tests/github-watcher-test.mjs` runs a real relay, real git with a real `origin`, and
|
|
6
|
-
the real MCP join, against a fake GitHub and a fake agent.
|
|
7
|
-
- **Mutants:** `scripts/github-mutants.mjs` removes each defence in turn and checks that its row
|
|
8
|
-
goes red.
|
|
9
|
-
- **Not yet run:** against a real repository with a real agent.
|
|
10
|
-
|
|
11
|
-
The tables below describe what the code does.
|
|
12
|
-
|
|
13
|
-
## What the user does
|
|
14
|
-
|
|
15
|
-
1. Once per repo, in their clone:
|
|
16
|
-
`npx -y hivecode-mcp@latest github start --agent "<agent command>"`
|
|
17
|
-
It checks that `gh` is logged in, that the agent command exists and can use Hivecode, and that the
|
|
18
|
-
labels exist, then keeps running and watches the repo.
|
|
19
|
-
**Private code:** every run puts the branch in a room on a relay, by default our public one.
|
|
20
|
-
Run your own (`npx -y hivecode-relay`, see docs/SELF_HOSTING.md) and add
|
|
21
|
-
`--relay wss://<your relay>`.
|
|
22
|
-
2. They label an issue `hivecode`.
|
|
23
|
-
3. A PR comes back, with:
|
|
24
|
-
- the issue's title;
|
|
25
|
-
- `Closes #12`;
|
|
26
|
-
- what changed and why;
|
|
27
|
-
- which tests ran and what they returned;
|
|
28
|
-
- one commit per agent.
|
|
29
|
-
4. If CI fails or they review the PR, the agent gets it and pushes fixes to the same PR.
|
|
30
|
-
- Inline comments and reviews always go to the agent.
|
|
31
|
-
- A plain comment goes only if it starts with `/hivecode`, so "thanks" or "LGTM" never spends a run.
|
|
32
|
-
5. They merge. To stop at any point, they remove the label or comment `/hivecode stop`.
|
|
33
|
-
`/hivecode retry` starts it again.
|
|
34
|
-
|
|
35
|
-
They never open a terminal for an issue and never watch a chat.
|
|
36
|
-
|
|
37
|
-
### See it first: `--dry-run`
|
|
38
|
-
|
|
39
|
-
`github start --dry-run` reads GitHub once. For each labelled issue it says what a start would do
|
|
40
|
-
and what is in the way. It writes nothing anywhere: no label, comment, branch, lock, watcher id or
|
|
41
|
-
state file, and it starts no agent. Use it first on a repo that matters. It is also the first
|
|
42
|
-
answer to "why isn't it picking up my issue?".
|
|
43
|
-
|
|
44
|
-
`--repo <folder>` points `start` or `status` at that clone, from any folder.
|
|
45
|
-
|
|
46
|
-
| what goes wrong | what the dry run does |
|
|
47
|
-
|---|---|
|
|
48
|
-
| A watcher has run on this clone before | It reads the state file as it is, and never moves or rewrites it. An issue that is in review, stopped, closed, or waiting for a person is reported as that, with what moves it on. It is never "would start now". |
|
|
49
|
-
| Today's runs are used up | It says "would wait: today's limit of 20 runs is reached". |
|
|
50
|
-
| Another watcher claimed the issue | It says "would skip". It reads the claim comment, as a start would. |
|
|
51
|
-
| This clone lost its state file, and the issue has our claim and an open PR | It says it would pick that PR up again, without a run. A start does exactly that. |
|
|
52
|
-
| A watcher is running on this clone right now | It says so first. A dry run takes no lock, so it neither stops nor blocks that watcher. |
|
|
53
|
-
| The state file says a run is going, and no watcher is alive | It says the run was cut off, and that a start runs it again. |
|
|
54
|
-
| The state file cannot be read | It leaves the file where it is, and says that a start would move it aside and rebuild from GitHub. `status` leaves it alone too. |
|
|
55
|
-
| GitHub fails to list the issues | It says so and exits 1. It never reports "no labelled issues". |
|
|
56
|
-
|
|
57
|
-
### Progress in Slack: `--slack-channel`
|
|
58
|
-
|
|
59
|
-
`github start --slack-channel C0123456789`, with the Slack app's bot token in `SLACK_BOT_TOKEN`,
|
|
60
|
-
gives each issue **one Slack thread**. The thread opens with the issue's number, title and link.
|
|
61
|
-
Inside it:
|
|
62
|
-
- each run starting;
|
|
63
|
-
- the pull request, which is also shown in the channel;
|
|
64
|
-
- CI failures;
|
|
65
|
-
- the tester's verdict;
|
|
66
|
-
- waiting for a person, which is also shown in the channel;
|
|
67
|
-
- merged or closed, also shown in the channel.
|
|
68
|
-
|
|
69
|
-
Setting up the Slack app is in [SLACK_SETUP.md](SLACK_SETUP.md).
|
|
70
|
-
|
|
71
|
-
| what goes wrong | what we do |
|
|
72
|
-
|---|---|
|
|
73
|
-
| No `SLACK_BOT_TOKEN` | `start` refuses with Q633 and the fix, before anything is written. |
|
|
74
|
-
| A token Slack refuses, or a bot that is not in the channel | Checked against Slack before any work starts (Q630, Q631), naming the `/invite` that fixes it. |
|
|
75
|
-
| Slack says "ready for review" for a PR that GitHub refused | Every post goes out only after the GitHub write it reports has succeeded. |
|
|
76
|
-
| A restart opens a second thread for the same issue | The thread id is kept in the watcher's state file, so a restart continues the same thread. |
|
|
77
|
-
| The room's id reaches Slack | It is never posted. Anyone with the id can read the code in the room, and Slack is outside it. |
|
|
78
|
-
| Slack is down, or the token is revoked mid-run | The work on GitHub goes on. The refusal is said once per reason, not once per post. |
|
|
79
|
-
| The token ends up somewhere it shouldn't | It is read from the environment only. It is never a flag, so it is never saved with the flags or left in shell history. |
|
|
80
|
-
| A secret in an agent's summary | Scrubbed before posting, the same as on GitHub. |
|
|
81
|
-
|
|
82
|
-
**Replies from Slack.** With `SLACK_APP_TOKEN` set as well (Socket Mode, so no public URL is
|
|
83
|
-
needed), a reply of `stop` in an issue's thread stops that issue. A reply of `retry` starts it
|
|
84
|
-
again, but only from the Slack user ids in `--slack-allow`. The watcher turns the reply into the
|
|
85
|
-
same `/hivecode stop` or `/hivecode retry` comment on the issue, "(from Slack, by @handle)". So one
|
|
86
|
-
command path acts on it, and GitHub keeps who asked.
|
|
87
|
-
|
|
88
|
-
| what goes wrong | what we do |
|
|
89
|
-
|---|---|
|
|
90
|
-
| A guest, or someone from another workspace (Slack Connect), replies `stop` | Refused, and told so in the thread. Who may is decided by the same rules as `slack start`, in one place in `hive-slack.js`. |
|
|
91
|
-
| A full member who is not in `--slack-allow` replies `retry` | Refused, and told so. Stopping is the safe direction, so any full member may stop, but only named people may start agents again. |
|
|
92
|
-
| Slack cannot confirm who replied `stop` (rate limit, outage) | It stops anyway, and says it could not confirm who asked. `retry` stays refused. |
|
|
93
|
-
| GitHub refuses the comment | Slack is told "Could not stop: GitHub refused". It never says "stopping" for a stop that did not happen. |
|
|
94
|
-
| A reply in a thread the watcher does not own | Ignored. |
|
|
95
|
-
| `--slack-allow` without `SLACK_APP_TOKEN` | Start refuses (Q634) and says to set it. Without it the replies are never read, so nobody could retry from Slack, while the start looked fine. |
|
|
96
|
-
| `--slack-allow` without `--slack-channel` | Start refuses (Q634): there are no threads to reply in. |
|
|
97
|
-
| `SLACK_APP_TOKEN` set, but the bot token lacks `users:read` or the channel's history scope (`channels:history`, or `groups:history` for a private channel) | Start refuses (Q634), names the missing scopes, and says to reinstall the app from `slack-app-manifest-inbound.json`. Without the history scope Slack never sends the replies, so a `stop` would silently do nothing; without `users:read` every stop is "unverified" and every retry refused. Slack reports a token's scopes on every answer; if it does not, start says so and goes on. |
|
|
98
|
-
| `--slack-allow ganesh` or `@ganesh` (a name, not a member id) | Start refuses (Q634) and says where the id is: profile, More, Copy member ID. Slack sends ids like `U012AB3CD`, so a name would never match and every retry would be refused. |
|
|
99
|
-
| A `--slack-allow` (or `--slack-channel`) saved by the last start, refused now | The error says it was saved by the last start, and that passing it empty (`--slack-allow ""`) drops it. Every flag is saved and used again by the next start. |
|
|
100
|
-
|
|
101
|
-
## How it works
|
|
102
|
-
|
|
103
|
-
The watcher is one process on a machine that has the clone, `gh` logged in, and an agent CLI:
|
|
104
|
-
Claude Code, Codex or Gemini CLI. That machine can be a laptop, a desktop or a VM.
|
|
105
|
-
|
|
106
|
-
Every minute it asks GitHub, through `gh`, what changed. Nothing has to reach in from outside, so it
|
|
107
|
-
works behind a company firewall, and no server of ours ever holds a GitHub key.
|
|
108
|
-
|
|
109
|
-
For each labelled issue:
|
|
110
|
-
|
|
111
|
-
| step | what happens |
|
|
112
|
-
|---|---|
|
|
113
|
-
| claim | It comments on the issue, with a hidden marker so no second watcher takes it, and creates the branch `hivecode/12-<slug>` from the default branch. |
|
|
114
|
-
| run | It opens a fresh room seeded from that branch and starts the agent with the task on stdin. It waits, with a time limit. |
|
|
115
|
-
| land | It makes one commit per agent on the branch and pushes. The first run opens the PR. Later runs push to that PR and comment on what they changed. |
|
|
116
|
-
| test | Optional `--test "<command>"`. The watcher runs the project's tests itself before pushing, so "tested" is a fact we checked, not the agent's word. |
|
|
117
|
-
| watch | It reads the CI result for the PR's newest commit, and the reviews and comments from people with write access. |
|
|
118
|
-
| loop | Each new CI failure, or batch of review comments, becomes the next run's task. The agent gets the failing job's log, not just "failed". A review becomes one run once nothing new has arrived for 90 s, not one run per comment. |
|
|
119
|
-
| finish | When the PR is merged or closed, it stops, removes the room folders and sends a notification. |
|
|
120
|
-
|
|
121
|
-
### Which agents
|
|
122
|
-
|
|
123
|
-
The agent command gets its task on stdin, from its working folder, and must end with the lines the
|
|
124
|
-
task asks for.
|
|
125
|
-
|
|
126
|
-
| agent | command | status |
|
|
127
|
-
|---|---|---|
|
|
128
|
-
| Claude Code | `claude -p --output-format json --allowedTools Bash Edit Write Read Glob Grep mcp__hivecode` | the default this was built for |
|
|
129
|
-
| Codex | `codex exec --skip-git-repo-check -s workspace-write -` | flags checked against its `--help`; not yet run end to end |
|
|
130
|
-
| Gemini CLI | `gemini -p "Do the task above." --approval-mode auto_edit` | flags checked against its `--help`; not yet run end to end |
|
|
131
|
-
|
|
132
|
-
Codex refuses to run outside a git repository unless given `--skip-git-repo-check`. A room's
|
|
133
|
-
folder is deliberately not a checkout, so the flag is required, not optional.
|
|
134
|
-
|
|
135
|
-
### A second agent checks the first (`--tester`)
|
|
136
|
-
|
|
137
|
-
`--tester "<command>"` adds a tester. It can be a different vendor's agent, so the check is
|
|
138
|
-
independent.
|
|
139
|
-
|
|
140
|
-
1. The builder runs, and its work lands on the local branch. Nothing is pushed yet.
|
|
141
|
-
2. The tester runs in a fresh room seeded from that branch, so it holds the change.
|
|
142
|
-
- It gets the issue and the builder's diff. The room's folder is not a git checkout, so it could
|
|
143
|
-
not see the diff otherwise.
|
|
144
|
-
- It may add or change tests only.
|
|
145
|
-
- It ends with `VERDICT: PASS` or `VERDICT: FAIL`, plus a report.
|
|
146
|
-
3. On PASS, its tests land, and the branch is pushed. The PR shows commits from both agents, and a
|
|
147
|
-
"Checked by Tester" section with the verdict and report.
|
|
148
|
-
4. On FAIL, nothing is pushed. Its report, and any failing test it wrote, become the builder's next
|
|
149
|
-
task. Then the tester checks again.
|
|
150
|
-
|
|
151
|
-
Every run counts against the caps, so a tester doubles what an issue costs.
|
|
152
|
-
|
|
153
|
-
Every run gets a new room, seeded from the branch as it is right now. So the room always includes
|
|
154
|
-
commits a person pushed to the branch, and a relay that loses its rooms costs at most the run in
|
|
155
|
-
progress. The watcher keeps its own state in the repo's `.git` folder, never on the relay.
|
|
156
|
-
|
|
157
|
-
Notifications are optional: one Slack or Discord webhook URL. They are sent when:
|
|
158
|
-
- a PR is ready;
|
|
159
|
-
- CI failed (the fix is under way);
|
|
160
|
-
- the issue needs you;
|
|
161
|
-
- the PR was merged or closed;
|
|
162
|
-
- CI has hung for two hours (once);
|
|
163
|
-
- the daily run limit is reached (once).
|
|
164
|
-
|
|
165
|
-
Nothing is sent for each comment.
|
|
166
|
-
|
|
167
|
-
## Room mode: multi-agent issues in a shared room
|
|
168
|
-
|
|
169
|
-
Room Mode hands labelled issues directly to agents already collaborating in a shared room bound to a branch.
|
|
170
|
-
Rather than spinning up isolated single-agent runs, the room's agents claim files, build, and review each other concurrently.
|
|
171
|
-
When work is complete and reviewed, Hivecode runs the project tests and opens or updates a single pull request.
|
|
172
|
-
|
|
173
|
-
### Setup
|
|
174
|
-
|
|
175
|
-
1. **Bind a room to a branch:**
|
|
176
|
-
```bash
|
|
177
|
-
npx -y hivecode-mcp@latest branch <branch-name>
|
|
178
|
-
```
|
|
179
|
-
This creates or binds a branch room on the relay and prints its join link (`wss://...|room-...`).
|
|
180
|
-
|
|
181
|
-
2. **Agents join the room:**
|
|
182
|
-
Connect your agents (Claude Code, Codex, Antigravity, or human developers) into the room using `hive_join` or the room link. Each agent gets its own workspace folder and display name.
|
|
183
|
-
|
|
184
|
-
3. **Start the room watcher:**
|
|
185
|
-
```bash
|
|
186
|
-
npx -y hivecode-mcp@latest github start --room "<room link>" [--fallback-agent "<command>"] [--ack-minutes 10]
|
|
187
|
-
```
|
|
188
|
-
The watcher polls GitHub for labelled issues and manages task dispatch and landings for that room.
|
|
189
|
-
|
|
190
|
-
### What the person sees on GitHub
|
|
191
|
-
|
|
192
|
-
Every event is posted in order on the issue or the pull request. Room identifiers and relay URLs are never posted on GitHub.
|
|
193
|
-
|
|
194
|
-
| event | where | what you see |
|
|
195
|
-
|---|---|---|
|
|
196
|
-
| Issue labelled `hivecode` | Issue comment | `Sent to room for branch <name>. In the room now: <agents>` (lists active agents and humans separately; skips passive bots). |
|
|
197
|
-
| Tests fail during landing | Issue comment | `tests failed, sent back to the room (attempt 1 of 2)`. The failing test output is posted as a task into the room. Unchanged code is not re-tested. |
|
|
198
|
-
| Work complete and reviewed | Pull request opened | PR titled after the issue (`<Title> (#1)`), body with `Closes #1`, summary of changed files, test verification (`Tests: npm test passed on <sha>, the exact commit pushed`), and one commit per author. |
|
|
199
|
-
| Issue updated with PR | Issue comment | `landed as PR #N` linking the pull request. |
|
|
200
|
-
| PR review feedback | PR comment & Room task | Comments on the PR become a single room task naming the blamed author (`Sent 1 review comment to the agents`). When fixed and reviewed, fixes are pushed to the same PR (`fixes pushed`). |
|
|
201
|
-
| Unresponsive or stuck | Issue comment & Label | If `--max-minutes` passes or retries exhaust (`--max-runs`), the issue is labelled `hivecode:needs-human` with the last room transcript lines. |
|
|
202
|
-
|
|
203
|
-
### `/hivecode stop` and `/hivecode retry`
|
|
204
|
-
|
|
205
|
-
- **/hivecode stop:** A comment starting with `/hivecode stop` on the issue or PR stops work immediately. It works mid-work: the room is notified, the active task is withdrawn, and nothing lands. A stop from someone who cannot push, or from before the run started, is ignored.
|
|
206
|
-
- **/hivecode retry:** A comment starting with `/hivecode retry` re-queues the issue. The watcher increments the attempt number and posts a new task (`Issue #12 (attempt 2): <title>`), matching the updated attempt so the room receives the retry cleanly without duplicate task suppression.
|
|
207
|
-
|
|
208
|
-
### Fallback agent and token cost
|
|
209
|
-
|
|
210
|
-
- **Opt-in only:** `--fallback-agent "<command>"` is strictly opt-in. Unattended agents never run unless explicitly configured.
|
|
211
|
-
- **Reachability & engagement gate:** If reachable agents are present in the room when an issue arrives, no fallback starts before `--ack-minutes` (default 10). If any agent engages (claims a file or chats intent), fallback is prevented. If 0 reachable agents exist at post time, fallback spawns immediately.
|
|
212
|
-
- **Budget caps:** Fallback runs are counted against `--max-runs-per-day` (default 20 across the repo) and run at most once per issue. When the daily limit is reached, no fallback spawns, and an issue comment notes that the limit was reached.
|
|
213
|
-
|
|
214
|
-
### The review rule and lone-agent waiver
|
|
215
|
-
|
|
216
|
-
- **Non-writer review required:** A task marked done will not land until a non-writer agent submits a passing review (`hive_review({ files, verdict: 'pass' })`). Reviews authored by contributors to the current held files are ignored.
|
|
217
|
-
- **Lone-agent waiver:** If only one agent is present in the room and no second agent arrives before `--ack-minutes` (default 10), Hivecode waives the second-agent requirement and lands the PR.
|
|
218
|
-
- **PR waiver notice:** The PR body explicitly states: `"not reviewed by a second agent"`, making the single-agent status transparent to human reviewers on GitHub. A `VERDICT: FAIL` review is never waived.
|
|
219
|
-
|
|
220
|
-
### Known limits
|
|
221
|
-
|
|
222
|
-
- **One issue at a time:** The watcher processes one issue at a time per room; subsequent labelled issues queue and wait for the active PR to be merged or closed.
|
|
223
|
-
- **One open PR:** The room maintains at most one open PR at a time to keep branch history and CRDT file states consistent.
|
|
224
|
-
- **Squash-merge history:** When PRs are squash-merged on GitHub, git commits are condensed to one, but GitHub preserves individual contributor names as `Co-authored-by:` trailers.
|
|
225
|
-
- **Antigravity multi-window MCP session sharing:** In Antigravity IDE, multiple windows on the same machine share a single background MCP server process. Parallel agents must use separate workspace folders and distinct agent names (e.g. `antigravity-2`, `antigravity-4`) or standalone sessions to avoid `.hive-mcp-session.json` identity collisions.
|
|
226
|
-
|
|
227
|
-
## Why `gh` and not a GitHub App, for now
|
|
228
|
-
|
|
229
|
-
- **With `gh`, nothing new is exposed.**
|
|
230
|
-
- There's no public endpoint to attack, and no private key on our relay.
|
|
231
|
-
- It works with a self-hosted relay inside a company network.
|
|
232
|
-
- It ships today, without waiting for an app to be registered.
|
|
233
|
-
- **Every API call is the user's own.** They can see each one and revoke it with `gh auth logout`.
|
|
234
|
-
- **The App comes next, for three things `gh` can't give:**
|
|
235
|
-
- PRs and comments from `hivecode[bot]` instead of the user. Under branch protection you cannot
|
|
236
|
-
approve your own PR.
|
|
237
|
-
- Instant webhooks instead of a one-minute poll.
|
|
238
|
-
- A listing on the GitHub Marketplace.
|
|
239
|
-
|
|
240
|
-
The watcher's design does not change. Only where events come from, and who signs the PR.
|
|
241
|
-
|
|
242
|
-
## What stays the same
|
|
243
|
-
|
|
244
|
-
- Git is the record, and the room is where the work happens.
|
|
245
|
-
- CI, required reviewers and branch protection all keep working as before.
|
|
246
|
-
- Agents never merge. A person does.
|
|
247
|
-
|
|
248
|
-
## What can go wrong, and what we do
|
|
249
|
-
|
|
250
|
-
"Wrong but green" is the failure this project keeps producing: it says it worked, and it didn't.
|
|
251
|
-
Each row below says what the user sees.
|
|
252
|
-
|
|
253
|
-
### GitHub
|
|
254
|
-
|
|
255
|
-
| what goes wrong | what we do |
|
|
256
|
-
|---|---|
|
|
257
|
-
| `gh` is missing, logged out, or its token can't do something | `start` refuses and prints the exact fix, e.g. `gh auth login`. A logged-out `gh` gives no HTTP answer at all, only "please run: gh auth login", so that text is read as a login problem (Q600), not as a network outage. If the login stops working later, the watcher holds off and logs it every minute. It also sends one notification, since nobody may be watching that terminal. |
|
|
258
|
-
| The repo doesn't exist, or it is private and the account `gh` uses can't see it | GitHub answers 404 for both. `start` says which repo and which account (Q601), and that a private repo needs an account with access. It doesn't say "is gh logged in?", because the login just worked. |
|
|
259
|
-
| The `origin` URL has a token in it (`https://x-access-token:<token>@...`) | A message that quotes the origin drops everything between `//` and `@`, so the token never reaches a log or a screenshot. |
|
|
260
|
-
| Someone runs `github --help` | Usage goes to stdout with exit 0, before git or GitHub is asked anything. |
|
|
261
|
-
| The `--notify` webhook URL leaks (anyone holding it can post as you) | Only its host is ever printed ("posted to hooks.slack.com"). Given with `--notify`, it is saved with the other flags so a restarted service keeps notifying, in a state file only its owner can read (on Mac and Linux). Given as `HIVE_NOTIFY_WEBHOOK`, it is never saved. Something that is not an http(s) address is refused at start (Q609). |
|
|
262
|
-
| A service manager restarts `github start` (systemd, launchd, Task Scheduler) | The exit code says whether a restart can help: 0 stopped cleanly; 1 GitHub or Slack could not be reached, was busy (5xx, rate limit), or it crashed, so try again; 2 a person must change something (a login, a permission, a flag, a token, or a copy already running). What cannot be told apart exits 1, because a machine that booted before its network came up must not be left without a watcher. Recipes that use this are in [ALWAYS_ON.md](ALWAYS_ON.md). |
|
|
263
|
-
| The `hivecode` label doesn't exist | `start` creates `hivecode` and `hivecode:needs-human`. |
|
|
264
|
-
| A read from GitHub fails (network, outage, 5xx) | **A failed read is never treated as "no issues" or "PR closed".** Nothing changes state on a failed read. We back off and retry, and status says so. |
|
|
265
|
-
| Rate limit, primary or secondary | We wait for `Retry-After` or the reset time and do nothing twice. Status shows it. |
|
|
266
|
-
| The label was added by someone who can't push (a stranger, or a bot) | Skipped. Status and the log name who labelled it. Only write, maintain or admin counts. |
|
|
267
|
-
| The "issue" is a pull request (the issues API returns both) | Skipped. |
|
|
268
|
-
| More than 100 labelled issues | We read every page. They queue oldest first; `--max-parallel` (default 1) run at once. Only a claimed issue gets a comment. |
|
|
269
|
-
| Two watchers on one repo (two terminals, two machines) | A lock file covers one machine. Across machines, the claim comment's marker does: whoever commented first owns the issue. |
|
|
270
|
-
| The branch name is already taken | We add `-2`, `-3`, … We never reuse a branch we didn't create. |
|
|
271
|
-
| Someone pushes to the PR branch | The next run's room is seeded from the branch, so it includes their commits. If they push during a run, our push is refused, nothing of theirs is overwritten, and the issue goes to needs-human. |
|
|
272
|
-
| The default branch moves on, and GitHub says the PR can't be merged | While the issue is idle in review, the watcher merges the default branch into the PR's branch in a worktree of its own, never your checkout, and pushes the merge commit. CI runs again on it. On a conflict it aborts, pushes nothing, and the issue goes to needs-human with the files named. One try per head commit. Repos that require linear history won't take a merge commit: there the push is refused, and that also goes to a person. Agents resolving conflicts comes later. |
|
|
273
|
-
| The issue is edited after it was picked up | Runs use the text as it was when claimed. `/hivecode retry` reads it again, so a person can clarify the issue and retry. |
|
|
274
|
-
| The issue or the PR is closed, or the label is removed | We stop. A run in progress is killed, and we don't push. |
|
|
275
|
-
| The PR is closed without merging, with the label left on | Nothing starts again: closing it is a "no". `/hivecode retry` starts a new attempt. |
|
|
276
|
-
| The PR is reopened | We watch it again. |
|
|
277
|
-
| A huge issue body, or images only | The text is cut to 20 KB, and the task tells the agent so. The task also says how many images the issue has, and that the agent cannot see them. |
|
|
278
|
-
| The state file is lost or unreadable | An unreadable file is set aside, never deleted, and the start says where it went (Q606). Each claim comment names its branch, so the watcher picks up its pull requests, and anything waiting for a person, without running anything again. |
|
|
279
|
-
| CI never finishes (a stuck job) | After 2 hours pending we notify once, and keep watching. |
|
|
280
|
-
| The repo has no CI | The PR waits for review. Nothing is assumed passed. |
|
|
281
|
-
|
|
282
|
-
### The agent
|
|
283
|
-
|
|
284
|
-
| what goes wrong | what we do |
|
|
285
|
-
|---|---|
|
|
286
|
-
| The agent CLI isn't installed | `start` refuses. |
|
|
287
|
-
| The agent is `claude` and has no `hivecode` MCP server (`setup` never ran on this machine), or has one that does not connect | `start` (and `--dry-run`) refuses (Q602) with `npx -y hivecode-mcp@latest setup`, after asking `claude mcp get hivecode`, which is read-only and spends no tokens. Without it the first run fails only after the user has paid for it. `claude` not answering in 60 s is said ("could not check"), never passed. `--skip-agent-check` is for a server set up under another name. |
|
|
288
|
-
| The agent command passes `--allowedTools` without `mcp__hivecode` | `start` refuses (Q602): in `-p` mode the hive tools would be denied, the same paid-for failure. |
|
|
289
|
-
| Any other agent CLI (Codex, Gemini) | `start` says it did not check it, never that it passed. |
|
|
290
|
-
| Logged out, usage limit, bad API key | The run fails fast. We retry once, after 15 minutes. A second failure in a row sends the issue to needs-human, with the agent's last lines in the comment and the notification. We never retry in a tight loop. |
|
|
291
|
-
| Codex refuses to start outside a git repository | A room's folder is deliberately not a git checkout. Its command needs `--skip-git-repo-check` (see "Which agents"). |
|
|
292
|
-
| The agent never joins its room (Hivecode isn't set up for that agent CLI) | Said as exactly that, with the setup command. Never reported as "no changes". |
|
|
293
|
-
| It runs forever: stuck, or waiting for a permission prompt in headless mode | A time limit per run (`--max-minutes`, default 40). We kill the whole process tree, push nothing, keep its folder for inspection, and mark the issue needs-human. |
|
|
294
|
-
| It finishes without changing anything | On a first run: no PR. We comment with its own last words and mark the issue needs-human. On a review run, a question answered needs no change: its answer is posted on the PR. |
|
|
295
|
-
| It has a question | Nobody answers during a run, and the task says so. It writes `BLOCKED: <question>` and stops. We post the question on the issue and notify. A reply from someone with write access starts the next run. |
|
|
296
|
-
| Its last edit didn't reach the room before it exited | Before landing, we reconnect its folder, under its own identity, to send anything still pending. Landing refuses to land part of a room (Q507). |
|
|
297
|
-
| It says the tests pass and they don't | With `--test`, we run them ourselves. A failure becomes the next run's task. Without `--test`, the PR body says the result is the agent's report, not ours. |
|
|
298
|
-
| The tester says nothing usable: no VERDICT, or "mostly passes" | Only `VERDICT: PASS` or `VERDICT: FAIL` counts. Anything else is a failed run, never a pass. It is retried once after 15 minutes, then goes to a person. |
|
|
299
|
-
| The tester fails the builder's work again and again | After three FAILs in a row it goes to a person, with the tester's last report. The run caps apply as well. |
|
|
300
|
-
| The tester edits the implementation, not just tests | It is told not to. If it does, the PR names those files under "Checked by", so a reviewer reads them with care. |
|
|
301
|
-
| The tester passes broken code | A PASS is the tester's word. The --test gate, then CI, still run after it, and a person reviews the PR. |
|
|
302
|
-
| It edits `.github/workflows/` | Refused unless `--allow-workflow-changes` is set. An agent misled by an issue could write a workflow that leaks the repo's secrets when CI runs. |
|
|
303
|
-
| It writes a key or token into a file | The room never carries a file with a key in it (hive-secrets.js), so the landing doesn't either. We also scan everything we post on GitHub. |
|
|
304
|
-
| A CI fix loop that never converges (a flaky test) | `--max-runs` per issue (default 6) and per day (default 20). If the same checks fail twice in a row, it goes to needs-human. |
|
|
305
|
-
| It pushes or opens a PR itself, bypassing the watcher | The task tells it not to. If it does anyway, nothing it pushed is overwritten: our push is refused, and the issue goes to a person. |
|
|
306
|
-
| It does damage outside the repo | On the user's own machine, an agent can do anything the user can. We say so plainly. To isolate it, run the watcher in a container or VM. |
|
|
307
|
-
| Prompt injection in an issue or a comment | Work starts only from a label someone with push access added. Only comments from people with write access are forwarded, checked against GitHub's permission for each person, not just their badge. The task quotes the issue as data from someone else. Agents can't merge, and a person reviews every PR. |
|
|
308
|
-
|
|
309
|
-
### The room and the relay
|
|
310
|
-
|
|
311
|
-
| what goes wrong | what we do |
|
|
312
|
-
|---|---|
|
|
313
|
-
| The relay is unreachable, or cold-starting (about 50 s on Render free) | The run doesn't start. We retry, and status says why. |
|
|
314
|
-
| The relay restarts mid-run and loses the room | The agent's folder still has its files, and its server refills the room when it reconnects. Landing checks that every file arrived (Q507). Worst case, we redo the run from the branch. |
|
|
315
|
-
| The public relay holds the code | Room ids are random (104 bits) and never posted on GitHub. `start` warns once when the repo is private and the relay is ours. Recommended: run your own relay (`npx hivecode-relay`). |
|
|
316
|
-
| A repo too big for a room | Rooms skip binaries and files over 1 MB, and agents on the watcher's machine fill those in from git. Past 5,000 files on the public relay, `start` refuses (Q608) and offers two ways out: your own relay, or `--allow-large`. |
|
|
317
|
-
|
|
318
|
-
### The machine
|
|
319
|
-
|
|
320
|
-
| what goes wrong | what we do |
|
|
321
|
-
|---|---|
|
|
322
|
-
| The laptop sleeps | Everything pauses. On wake we push each deadline back by the time asleep, so a sleeping run is not killed for being slow. For 24/7, run on a machine that stays on. |
|
|
323
|
-
| The watcher crashes, or Ctrl+C | It kills its agents' process trees on the way out. On restart, a run marked running whose process is gone counts as a failed run and is retried. |
|
|
324
|
-
| Windows | Agent CLIs are `.cmd` shims, so we start them through the shell. The prompt goes on stdin, never on the command line, so no quoting can break it. Process trees are killed with `taskkill /T`. |
|
|
325
|
-
| git asks for a password, or a credential manager opens a login window, and nobody is there to answer | Git is never allowed to prompt (`GIT_TERMINAL_PROMPT=0`, `GCM_INTERACTIVE=never`), so it fails at once instead of hanging. The error says to run `gh auth setup-git`, and the issue goes to a person rather than retrying every two minutes. |
|
|
326
|
-
| The home folder is itself a git repository, and `start` is run outside the project | `start` says exactly that, instead of a puzzling "origin (none)". |
|
|
327
|
-
| The repo has its own git hooks (husky, lefthook, a tool's post-checkout hook) | Hivecode's own scratch worktrees run without them: landing, the catch-up merge and the test gate. A hook that failed there made landing fail although git had done its job, and others run installs in a folder about to be deleted. The developer's checkout and every push keep their hooks. |
|
|
328
|
-
| The disk fills with room folders | Finished issues' folders are removed. Only the last failed run's folder is kept. |
|
|
329
|
-
|
|
330
|
-
### People
|
|
331
|
-
|
|
332
|
-
| what goes wrong | what we do |
|
|
333
|
-
|---|---|
|
|
334
|
-
| They comment while a run is going | It waits for the next run. One run per issue at a time. |
|
|
335
|
-
| They merge while a fix run is going | We kill the run, push nothing, and finish. |
|
|
336
|
-
| They want everything stopped | Remove the label, comment `/hivecode stop`, or Ctrl+C the watcher. |
|
|
337
|
-
| Notifications become noise | One per change of state, never one per comment. |
|
|
338
|
-
| They write "thanks" or "LGTM" on the PR | Nothing runs. Only reviews, inline comments, and comments starting with `/hivecode` go to the agent. |
|
|
339
|
-
| They can't approve the PR (it's theirs, under branch protection) | Said in the docs. The GitHub App fixes it. |
|
|
340
|
-
| A squash merge | GitHub keeps co-authors in the squash commit. The per-agent commits stay visible in the PR. |
|
|
341
|
-
|
|
342
|
-
### When real users arrive
|
|
343
|
-
|
|
344
|
-
| what goes wrong | what we do |
|
|
345
|
-
|---|---|
|
|
346
|
-
| A stranger's private code on our public relay | The warning above, plus `--relay` in the first line of the docs. |
|
|
347
|
-
| Their tokens get spent without them | Runs only start from a label. Every run is capped and counted, and `github status` shows today's runs. |
|
|
348
|
-
| A support question | Every refusal has a Q-code and the exact command that fixes it. |
|
|
349
|
-
| Mixed versions | The agent's own Hivecode must know branch rooms (`hive_join` with `branch`). Landing needs signed receipts, which every such runtime has. |
|
|
350
|
-
| Mac, Linux and Windows | The tests run on all three, through the existing Mac/Linux workflow. |
|
|
351
|
-
|
|
352
|
-
## Defaults
|
|
353
|
-
|
|
354
|
-
| setting | default |
|
|
355
|
-
|---|---|
|
|
356
|
-
| `--label` | `hivecode` |
|
|
357
|
-
| `--every` | 60 s |
|
|
358
|
-
| `--max-parallel` | 1 issue |
|
|
359
|
-
| `--max-minutes` | 40 per run |
|
|
360
|
-
| `--max-runs` | 6 per issue, 20 per day |
|
|
361
|
-
| `--relay` | the public relay; self-hosted recommended for private code |
|
|
362
|
-
| `--test` | off; the PR says the test result is the agent's report |
|
|
363
|
-
| `--repo` | the folder it is started in |
|
|
364
|
-
| `--dry-run` | off |
|
|
365
|
-
| `--slack-channel` | off; the token comes from `SLACK_BOT_TOKEN` |
|
|
366
|
-
|
|
367
|
-
## Build order
|
|
368
|
-
|
|
369
|
-
All built on 13 Oct 2026:
|
|
370
|
-
1. The watcher core: claim, run, land, PR, with caps and state.
|
|
371
|
-
2. The loop: CI results and trusted comments become the next run.
|
|
372
|
-
3. Kill switches and needs-human.
|
|
373
|
-
4. Notifications.
|
|
374
|
-
5. `github status`.
|
|
375
|
-
6. Docs, plus this file kept true.
|
|
376
|
-
|
|
377
|
-
## How it is tested
|
|
378
|
-
|
|
379
|
-
- `tests/github-watcher-test.mjs` runs everything for real except GitHub and the agent: a local
|
|
380
|
-
relay, a real git repo with a local `origin`, a fake GitHub inside the test, and a fake agent that
|
|
381
|
-
joins its room through the real MCP server code. It spends no tokens and touches no real repo.
|
|
382
|
-
- `tests/github-cli-test.mjs` checks what a stranger meets first: each refusal and its fix, and the
|
|
383
|
-
dry run, both on a fresh clone and on one a watcher has worked in.
|
|
384
|
-
- `scripts/github-mutants.mjs` removes each important defence in turn, and its check has to go red.
|
|
385
|
-
A defence whose check stays green is not covered, whatever the test claims.
|
|
386
|
-
|
|
387
|
-
## Not in this version
|
|
388
|
-
|
|
389
|
-
- More than one builder working the same issue at once. The tester runs after the builder, not
|
|
390
|
-
beside it.
|
|
391
|
-
- The GitHub App: bot identity, webhooks, Marketplace. It needs Ganesh's account.
|
|
392
|
-
- Agents resolving merge conflicts.
|
|
393
|
-
- One watcher for several repos.
|
|
394
|
-
- Always-on hosting, on a VM or Maritime. The watcher is the piece that would run there.
|
|
1
|
+
# GitHub workflow: label an issue, get back a tested PR
|
|
2
|
+
|
|
3
|
+
Status, 13 Oct 2026:
|
|
4
|
+
- **Built:** the watcher (`hive-github.js`).
|
|
5
|
+
- **Tested:** `tests/github-watcher-test.mjs` runs a real relay, real git with a real `origin`, and
|
|
6
|
+
the real MCP join, against a fake GitHub and a fake agent.
|
|
7
|
+
- **Mutants:** `scripts/github-mutants.mjs` removes each defence in turn and checks that its row
|
|
8
|
+
goes red.
|
|
9
|
+
- **Not yet run:** against a real repository with a real agent.
|
|
10
|
+
|
|
11
|
+
The tables below describe what the code does.
|
|
12
|
+
|
|
13
|
+
## What the user does
|
|
14
|
+
|
|
15
|
+
1. Once per repo, in their clone:
|
|
16
|
+
`npx -y hivecode-mcp@latest github start --agent "<agent command>"`
|
|
17
|
+
It checks that `gh` is logged in, that the agent command exists and can use Hivecode, and that the
|
|
18
|
+
labels exist, then keeps running and watches the repo.
|
|
19
|
+
**Private code:** every run puts the branch in a room on a relay, by default our public one.
|
|
20
|
+
Run your own (`npx -y hivecode-relay`, see docs/SELF_HOSTING.md) and add
|
|
21
|
+
`--relay wss://<your relay>`.
|
|
22
|
+
2. They label an issue `hivecode`.
|
|
23
|
+
3. A PR comes back, with:
|
|
24
|
+
- the issue's title;
|
|
25
|
+
- `Closes #12`;
|
|
26
|
+
- what changed and why;
|
|
27
|
+
- which tests ran and what they returned;
|
|
28
|
+
- one commit per agent.
|
|
29
|
+
4. If CI fails or they review the PR, the agent gets it and pushes fixes to the same PR.
|
|
30
|
+
- Inline comments and reviews always go to the agent.
|
|
31
|
+
- A plain comment goes only if it starts with `/hivecode`, so "thanks" or "LGTM" never spends a run.
|
|
32
|
+
5. They merge. To stop at any point, they remove the label or comment `/hivecode stop`.
|
|
33
|
+
`/hivecode retry` starts it again.
|
|
34
|
+
|
|
35
|
+
They never open a terminal for an issue and never watch a chat.
|
|
36
|
+
|
|
37
|
+
### See it first: `--dry-run`
|
|
38
|
+
|
|
39
|
+
`github start --dry-run` reads GitHub once. For each labelled issue it says what a start would do
|
|
40
|
+
and what is in the way. It writes nothing anywhere: no label, comment, branch, lock, watcher id or
|
|
41
|
+
state file, and it starts no agent. Use it first on a repo that matters. It is also the first
|
|
42
|
+
answer to "why isn't it picking up my issue?".
|
|
43
|
+
|
|
44
|
+
`--repo <folder>` points `start` or `status` at that clone, from any folder.
|
|
45
|
+
|
|
46
|
+
| what goes wrong | what the dry run does |
|
|
47
|
+
|---|---|
|
|
48
|
+
| A watcher has run on this clone before | It reads the state file as it is, and never moves or rewrites it. An issue that is in review, stopped, closed, or waiting for a person is reported as that, with what moves it on. It is never "would start now". |
|
|
49
|
+
| Today's runs are used up | It says "would wait: today's limit of 20 runs is reached". |
|
|
50
|
+
| Another watcher claimed the issue | It says "would skip". It reads the claim comment, as a start would. |
|
|
51
|
+
| This clone lost its state file, and the issue has our claim and an open PR | It says it would pick that PR up again, without a run. A start does exactly that. |
|
|
52
|
+
| A watcher is running on this clone right now | It says so first. A dry run takes no lock, so it neither stops nor blocks that watcher. |
|
|
53
|
+
| The state file says a run is going, and no watcher is alive | It says the run was cut off, and that a start runs it again. |
|
|
54
|
+
| The state file cannot be read | It leaves the file where it is, and says that a start would move it aside and rebuild from GitHub. `status` leaves it alone too. |
|
|
55
|
+
| GitHub fails to list the issues | It says so and exits 1. It never reports "no labelled issues". |
|
|
56
|
+
|
|
57
|
+
### Progress in Slack: `--slack-channel`
|
|
58
|
+
|
|
59
|
+
`github start --slack-channel C0123456789`, with the Slack app's bot token in `SLACK_BOT_TOKEN`,
|
|
60
|
+
gives each issue **one Slack thread**. The thread opens with the issue's number, title and link.
|
|
61
|
+
Inside it:
|
|
62
|
+
- each run starting;
|
|
63
|
+
- the pull request, which is also shown in the channel;
|
|
64
|
+
- CI failures;
|
|
65
|
+
- the tester's verdict;
|
|
66
|
+
- waiting for a person, which is also shown in the channel;
|
|
67
|
+
- merged or closed, also shown in the channel.
|
|
68
|
+
|
|
69
|
+
Setting up the Slack app is in [SLACK_SETUP.md](SLACK_SETUP.md).
|
|
70
|
+
|
|
71
|
+
| what goes wrong | what we do |
|
|
72
|
+
|---|---|
|
|
73
|
+
| No `SLACK_BOT_TOKEN` | `start` refuses with Q633 and the fix, before anything is written. |
|
|
74
|
+
| A token Slack refuses, or a bot that is not in the channel | Checked against Slack before any work starts (Q630, Q631), naming the `/invite` that fixes it. |
|
|
75
|
+
| Slack says "ready for review" for a PR that GitHub refused | Every post goes out only after the GitHub write it reports has succeeded. |
|
|
76
|
+
| A restart opens a second thread for the same issue | The thread id is kept in the watcher's state file, so a restart continues the same thread. |
|
|
77
|
+
| The room's id reaches Slack | It is never posted. Anyone with the id can read the code in the room, and Slack is outside it. |
|
|
78
|
+
| Slack is down, or the token is revoked mid-run | The work on GitHub goes on. The refusal is said once per reason, not once per post. |
|
|
79
|
+
| The token ends up somewhere it shouldn't | It is read from the environment only. It is never a flag, so it is never saved with the flags or left in shell history. |
|
|
80
|
+
| A secret in an agent's summary | Scrubbed before posting, the same as on GitHub. |
|
|
81
|
+
|
|
82
|
+
**Replies from Slack.** With `SLACK_APP_TOKEN` set as well (Socket Mode, so no public URL is
|
|
83
|
+
needed), a reply of `stop` in an issue's thread stops that issue. A reply of `retry` starts it
|
|
84
|
+
again, but only from the Slack user ids in `--slack-allow`. The watcher turns the reply into the
|
|
85
|
+
same `/hivecode stop` or `/hivecode retry` comment on the issue, "(from Slack, by @handle)". So one
|
|
86
|
+
command path acts on it, and GitHub keeps who asked.
|
|
87
|
+
|
|
88
|
+
| what goes wrong | what we do |
|
|
89
|
+
|---|---|
|
|
90
|
+
| A guest, or someone from another workspace (Slack Connect), replies `stop` | Refused, and told so in the thread. Who may is decided by the same rules as `slack start`, in one place in `hive-slack.js`. |
|
|
91
|
+
| A full member who is not in `--slack-allow` replies `retry` | Refused, and told so. Stopping is the safe direction, so any full member may stop, but only named people may start agents again. |
|
|
92
|
+
| Slack cannot confirm who replied `stop` (rate limit, outage) | It stops anyway, and says it could not confirm who asked. `retry` stays refused. |
|
|
93
|
+
| GitHub refuses the comment | Slack is told "Could not stop: GitHub refused". It never says "stopping" for a stop that did not happen. |
|
|
94
|
+
| A reply in a thread the watcher does not own | Ignored. |
|
|
95
|
+
| `--slack-allow` without `SLACK_APP_TOKEN` | Start refuses (Q634) and says to set it. Without it the replies are never read, so nobody could retry from Slack, while the start looked fine. |
|
|
96
|
+
| `--slack-allow` without `--slack-channel` | Start refuses (Q634): there are no threads to reply in. |
|
|
97
|
+
| `SLACK_APP_TOKEN` set, but the bot token lacks `users:read` or the channel's history scope (`channels:history`, or `groups:history` for a private channel) | Start refuses (Q634), names the missing scopes, and says to reinstall the app from `slack-app-manifest-inbound.json`. Without the history scope Slack never sends the replies, so a `stop` would silently do nothing; without `users:read` every stop is "unverified" and every retry refused. Slack reports a token's scopes on every answer; if it does not, start says so and goes on. |
|
|
98
|
+
| `--slack-allow ganesh` or `@ganesh` (a name, not a member id) | Start refuses (Q634) and says where the id is: profile, More, Copy member ID. Slack sends ids like `U012AB3CD`, so a name would never match and every retry would be refused. |
|
|
99
|
+
| A `--slack-allow` (or `--slack-channel`) saved by the last start, refused now | The error says it was saved by the last start, and that passing it empty (`--slack-allow ""`) drops it. Every flag is saved and used again by the next start. |
|
|
100
|
+
|
|
101
|
+
## How it works
|
|
102
|
+
|
|
103
|
+
The watcher is one process on a machine that has the clone, `gh` logged in, and an agent CLI:
|
|
104
|
+
Claude Code, Codex or Gemini CLI. That machine can be a laptop, a desktop or a VM.
|
|
105
|
+
|
|
106
|
+
Every minute it asks GitHub, through `gh`, what changed. Nothing has to reach in from outside, so it
|
|
107
|
+
works behind a company firewall, and no server of ours ever holds a GitHub key.
|
|
108
|
+
|
|
109
|
+
For each labelled issue:
|
|
110
|
+
|
|
111
|
+
| step | what happens |
|
|
112
|
+
|---|---|
|
|
113
|
+
| claim | It comments on the issue, with a hidden marker so no second watcher takes it, and creates the branch `hivecode/12-<slug>` from the default branch. |
|
|
114
|
+
| run | It opens a fresh room seeded from that branch and starts the agent with the task on stdin. It waits, with a time limit. |
|
|
115
|
+
| land | It makes one commit per agent on the branch and pushes. The first run opens the PR. Later runs push to that PR and comment on what they changed. |
|
|
116
|
+
| test | Optional `--test "<command>"`. The watcher runs the project's tests itself before pushing, so "tested" is a fact we checked, not the agent's word. |
|
|
117
|
+
| watch | It reads the CI result for the PR's newest commit, and the reviews and comments from people with write access. |
|
|
118
|
+
| loop | Each new CI failure, or batch of review comments, becomes the next run's task. The agent gets the failing job's log, not just "failed". A review becomes one run once nothing new has arrived for 90 s, not one run per comment. |
|
|
119
|
+
| finish | When the PR is merged or closed, it stops, removes the room folders and sends a notification. |
|
|
120
|
+
|
|
121
|
+
### Which agents
|
|
122
|
+
|
|
123
|
+
The agent command gets its task on stdin, from its working folder, and must end with the lines the
|
|
124
|
+
task asks for.
|
|
125
|
+
|
|
126
|
+
| agent | command | status |
|
|
127
|
+
|---|---|---|
|
|
128
|
+
| Claude Code | `claude -p --output-format json --allowedTools Bash Edit Write Read Glob Grep mcp__hivecode` | the default this was built for |
|
|
129
|
+
| Codex | `codex exec --skip-git-repo-check -s workspace-write -` | flags checked against its `--help`; not yet run end to end |
|
|
130
|
+
| Gemini CLI | `gemini -p "Do the task above." --approval-mode auto_edit` | flags checked against its `--help`; not yet run end to end |
|
|
131
|
+
|
|
132
|
+
Codex refuses to run outside a git repository unless given `--skip-git-repo-check`. A room's
|
|
133
|
+
folder is deliberately not a checkout, so the flag is required, not optional.
|
|
134
|
+
|
|
135
|
+
### A second agent checks the first (`--tester`)
|
|
136
|
+
|
|
137
|
+
`--tester "<command>"` adds a tester. It can be a different vendor's agent, so the check is
|
|
138
|
+
independent.
|
|
139
|
+
|
|
140
|
+
1. The builder runs, and its work lands on the local branch. Nothing is pushed yet.
|
|
141
|
+
2. The tester runs in a fresh room seeded from that branch, so it holds the change.
|
|
142
|
+
- It gets the issue and the builder's diff. The room's folder is not a git checkout, so it could
|
|
143
|
+
not see the diff otherwise.
|
|
144
|
+
- It may add or change tests only.
|
|
145
|
+
- It ends with `VERDICT: PASS` or `VERDICT: FAIL`, plus a report.
|
|
146
|
+
3. On PASS, its tests land, and the branch is pushed. The PR shows commits from both agents, and a
|
|
147
|
+
"Checked by Tester" section with the verdict and report.
|
|
148
|
+
4. On FAIL, nothing is pushed. Its report, and any failing test it wrote, become the builder's next
|
|
149
|
+
task. Then the tester checks again.
|
|
150
|
+
|
|
151
|
+
Every run counts against the caps, so a tester doubles what an issue costs.
|
|
152
|
+
|
|
153
|
+
Every run gets a new room, seeded from the branch as it is right now. So the room always includes
|
|
154
|
+
commits a person pushed to the branch, and a relay that loses its rooms costs at most the run in
|
|
155
|
+
progress. The watcher keeps its own state in the repo's `.git` folder, never on the relay.
|
|
156
|
+
|
|
157
|
+
Notifications are optional: one Slack or Discord webhook URL. They are sent when:
|
|
158
|
+
- a PR is ready;
|
|
159
|
+
- CI failed (the fix is under way);
|
|
160
|
+
- the issue needs you;
|
|
161
|
+
- the PR was merged or closed;
|
|
162
|
+
- CI has hung for two hours (once);
|
|
163
|
+
- the daily run limit is reached (once).
|
|
164
|
+
|
|
165
|
+
Nothing is sent for each comment.
|
|
166
|
+
|
|
167
|
+
## Room mode: multi-agent issues in a shared room
|
|
168
|
+
|
|
169
|
+
Room Mode hands labelled issues directly to agents already collaborating in a shared room bound to a branch.
|
|
170
|
+
Rather than spinning up isolated single-agent runs, the room's agents claim files, build, and review each other concurrently.
|
|
171
|
+
When work is complete and reviewed, Hivecode runs the project tests and opens or updates a single pull request.
|
|
172
|
+
|
|
173
|
+
### Setup
|
|
174
|
+
|
|
175
|
+
1. **Bind a room to a branch:**
|
|
176
|
+
```bash
|
|
177
|
+
npx -y hivecode-mcp@latest branch <branch-name>
|
|
178
|
+
```
|
|
179
|
+
This creates or binds a branch room on the relay and prints its join link (`wss://...|room-...`).
|
|
180
|
+
|
|
181
|
+
2. **Agents join the room:**
|
|
182
|
+
Connect your agents (Claude Code, Codex, Antigravity, or human developers) into the room using `hive_join` or the room link. Each agent gets its own workspace folder and display name.
|
|
183
|
+
|
|
184
|
+
3. **Start the room watcher:**
|
|
185
|
+
```bash
|
|
186
|
+
npx -y hivecode-mcp@latest github start --room "<room link>" [--fallback-agent "<command>"] [--ack-minutes 10]
|
|
187
|
+
```
|
|
188
|
+
The watcher polls GitHub for labelled issues and manages task dispatch and landings for that room.
|
|
189
|
+
|
|
190
|
+
### What the person sees on GitHub
|
|
191
|
+
|
|
192
|
+
Every event is posted in order on the issue or the pull request. Room identifiers and relay URLs are never posted on GitHub.
|
|
193
|
+
|
|
194
|
+
| event | where | what you see |
|
|
195
|
+
|---|---|---|
|
|
196
|
+
| Issue labelled `hivecode` | Issue comment | `Sent to room for branch <name>. In the room now: <agents>` (lists active agents and humans separately; skips passive bots). |
|
|
197
|
+
| Tests fail during landing | Issue comment | `tests failed, sent back to the room (attempt 1 of 2)`. The failing test output is posted as a task into the room. Unchanged code is not re-tested. |
|
|
198
|
+
| Work complete and reviewed | Pull request opened | PR titled after the issue (`<Title> (#1)`), body with `Closes #1`, summary of changed files, test verification (`Tests: npm test passed on <sha>, the exact commit pushed`), and one commit per author. |
|
|
199
|
+
| Issue updated with PR | Issue comment | `landed as PR #N` linking the pull request. |
|
|
200
|
+
| PR review feedback | PR comment & Room task | Comments on the PR become a single room task naming the blamed author (`Sent 1 review comment to the agents`). When fixed and reviewed, fixes are pushed to the same PR (`fixes pushed`). |
|
|
201
|
+
| Unresponsive or stuck | Issue comment & Label | If `--max-minutes` passes or retries exhaust (`--max-runs`), the issue is labelled `hivecode:needs-human` with the last room transcript lines. |
|
|
202
|
+
|
|
203
|
+
### `/hivecode stop` and `/hivecode retry`
|
|
204
|
+
|
|
205
|
+
- **/hivecode stop:** A comment starting with `/hivecode stop` on the issue or PR stops work immediately. It works mid-work: the room is notified, the active task is withdrawn, and nothing lands. A stop from someone who cannot push, or from before the run started, is ignored.
|
|
206
|
+
- **/hivecode retry:** A comment starting with `/hivecode retry` re-queues the issue. The watcher increments the attempt number and posts a new task (`Issue #12 (attempt 2): <title>`), matching the updated attempt so the room receives the retry cleanly without duplicate task suppression.
|
|
207
|
+
|
|
208
|
+
### Fallback agent and token cost
|
|
209
|
+
|
|
210
|
+
- **Opt-in only:** `--fallback-agent "<command>"` is strictly opt-in. Unattended agents never run unless explicitly configured.
|
|
211
|
+
- **Reachability & engagement gate:** If reachable agents are present in the room when an issue arrives, no fallback starts before `--ack-minutes` (default 10). If any agent engages (claims a file or chats intent), fallback is prevented. If 0 reachable agents exist at post time, fallback spawns immediately.
|
|
212
|
+
- **Budget caps:** Fallback runs are counted against `--max-runs-per-day` (default 20 across the repo) and run at most once per issue. When the daily limit is reached, no fallback spawns, and an issue comment notes that the limit was reached.
|
|
213
|
+
|
|
214
|
+
### The review rule and lone-agent waiver
|
|
215
|
+
|
|
216
|
+
- **Non-writer review required:** A task marked done will not land until a non-writer agent submits a passing review (`hive_review({ files, verdict: 'pass' })`). Reviews authored by contributors to the current held files are ignored.
|
|
217
|
+
- **Lone-agent waiver:** If only one agent is present in the room and no second agent arrives before `--ack-minutes` (default 10), Hivecode waives the second-agent requirement and lands the PR.
|
|
218
|
+
- **PR waiver notice:** The PR body explicitly states: `"not reviewed by a second agent"`, making the single-agent status transparent to human reviewers on GitHub. A `VERDICT: FAIL` review is never waived.
|
|
219
|
+
|
|
220
|
+
### Known limits
|
|
221
|
+
|
|
222
|
+
- **One issue at a time:** The watcher processes one issue at a time per room; subsequent labelled issues queue and wait for the active PR to be merged or closed.
|
|
223
|
+
- **One open PR:** The room maintains at most one open PR at a time to keep branch history and CRDT file states consistent.
|
|
224
|
+
- **Squash-merge history:** When PRs are squash-merged on GitHub, git commits are condensed to one, but GitHub preserves individual contributor names as `Co-authored-by:` trailers.
|
|
225
|
+
- **Antigravity multi-window MCP session sharing:** In Antigravity IDE, multiple windows on the same machine share a single background MCP server process. Parallel agents must use separate workspace folders and distinct agent names (e.g. `antigravity-2`, `antigravity-4`) or standalone sessions to avoid `.hive-mcp-session.json` identity collisions.
|
|
226
|
+
|
|
227
|
+
## Why `gh` and not a GitHub App, for now
|
|
228
|
+
|
|
229
|
+
- **With `gh`, nothing new is exposed.**
|
|
230
|
+
- There's no public endpoint to attack, and no private key on our relay.
|
|
231
|
+
- It works with a self-hosted relay inside a company network.
|
|
232
|
+
- It ships today, without waiting for an app to be registered.
|
|
233
|
+
- **Every API call is the user's own.** They can see each one and revoke it with `gh auth logout`.
|
|
234
|
+
- **The App comes next, for three things `gh` can't give:**
|
|
235
|
+
- PRs and comments from `hivecode[bot]` instead of the user. Under branch protection you cannot
|
|
236
|
+
approve your own PR.
|
|
237
|
+
- Instant webhooks instead of a one-minute poll.
|
|
238
|
+
- A listing on the GitHub Marketplace.
|
|
239
|
+
|
|
240
|
+
The watcher's design does not change. Only where events come from, and who signs the PR.
|
|
241
|
+
|
|
242
|
+
## What stays the same
|
|
243
|
+
|
|
244
|
+
- Git is the record, and the room is where the work happens.
|
|
245
|
+
- CI, required reviewers and branch protection all keep working as before.
|
|
246
|
+
- Agents never merge. A person does.
|
|
247
|
+
|
|
248
|
+
## What can go wrong, and what we do
|
|
249
|
+
|
|
250
|
+
"Wrong but green" is the failure this project keeps producing: it says it worked, and it didn't.
|
|
251
|
+
Each row below says what the user sees.
|
|
252
|
+
|
|
253
|
+
### GitHub
|
|
254
|
+
|
|
255
|
+
| what goes wrong | what we do |
|
|
256
|
+
|---|---|
|
|
257
|
+
| `gh` is missing, logged out, or its token can't do something | `start` refuses and prints the exact fix, e.g. `gh auth login`. A logged-out `gh` gives no HTTP answer at all, only "please run: gh auth login", so that text is read as a login problem (Q600), not as a network outage. If the login stops working later, the watcher holds off and logs it every minute. It also sends one notification, since nobody may be watching that terminal. |
|
|
258
|
+
| The repo doesn't exist, or it is private and the account `gh` uses can't see it | GitHub answers 404 for both. `start` says which repo and which account (Q601), and that a private repo needs an account with access. It doesn't say "is gh logged in?", because the login just worked. |
|
|
259
|
+
| The `origin` URL has a token in it (`https://x-access-token:<token>@...`) | A message that quotes the origin drops everything between `//` and `@`, so the token never reaches a log or a screenshot. |
|
|
260
|
+
| Someone runs `github --help` | Usage goes to stdout with exit 0, before git or GitHub is asked anything. |
|
|
261
|
+
| The `--notify` webhook URL leaks (anyone holding it can post as you) | Only its host is ever printed ("posted to hooks.slack.com"). Given with `--notify`, it is saved with the other flags so a restarted service keeps notifying, in a state file only its owner can read (on Mac and Linux). Given as `HIVE_NOTIFY_WEBHOOK`, it is never saved. Something that is not an http(s) address is refused at start (Q609). |
|
|
262
|
+
| A service manager restarts `github start` (systemd, launchd, Task Scheduler) | The exit code says whether a restart can help: 0 stopped cleanly; 1 GitHub or Slack could not be reached, was busy (5xx, rate limit), or it crashed, so try again; 2 a person must change something (a login, a permission, a flag, a token, or a copy already running). What cannot be told apart exits 1, because a machine that booted before its network came up must not be left without a watcher. Recipes that use this are in [ALWAYS_ON.md](ALWAYS_ON.md). |
|
|
263
|
+
| The `hivecode` label doesn't exist | `start` creates `hivecode` and `hivecode:needs-human`. |
|
|
264
|
+
| A read from GitHub fails (network, outage, 5xx) | **A failed read is never treated as "no issues" or "PR closed".** Nothing changes state on a failed read. We back off and retry, and status says so. |
|
|
265
|
+
| Rate limit, primary or secondary | We wait for `Retry-After` or the reset time and do nothing twice. Status shows it. |
|
|
266
|
+
| The label was added by someone who can't push (a stranger, or a bot) | Skipped. Status and the log name who labelled it. Only write, maintain or admin counts. |
|
|
267
|
+
| The "issue" is a pull request (the issues API returns both) | Skipped. |
|
|
268
|
+
| More than 100 labelled issues | We read every page. They queue oldest first; `--max-parallel` (default 1) run at once. Only a claimed issue gets a comment. |
|
|
269
|
+
| Two watchers on one repo (two terminals, two machines) | A lock file covers one machine. Across machines, the claim comment's marker does: whoever commented first owns the issue. |
|
|
270
|
+
| The branch name is already taken | We add `-2`, `-3`, … We never reuse a branch we didn't create. |
|
|
271
|
+
| Someone pushes to the PR branch | The next run's room is seeded from the branch, so it includes their commits. If they push during a run, our push is refused, nothing of theirs is overwritten, and the issue goes to needs-human. |
|
|
272
|
+
| The default branch moves on, and GitHub says the PR can't be merged | While the issue is idle in review, the watcher merges the default branch into the PR's branch in a worktree of its own, never your checkout, and pushes the merge commit. CI runs again on it. On a conflict it aborts, pushes nothing, and the issue goes to needs-human with the files named. One try per head commit. Repos that require linear history won't take a merge commit: there the push is refused, and that also goes to a person. Agents resolving conflicts comes later. |
|
|
273
|
+
| The issue is edited after it was picked up | Runs use the text as it was when claimed. `/hivecode retry` reads it again, so a person can clarify the issue and retry. |
|
|
274
|
+
| The issue or the PR is closed, or the label is removed | We stop. A run in progress is killed, and we don't push. |
|
|
275
|
+
| The PR is closed without merging, with the label left on | Nothing starts again: closing it is a "no". `/hivecode retry` starts a new attempt. |
|
|
276
|
+
| The PR is reopened | We watch it again. |
|
|
277
|
+
| A huge issue body, or images only | The text is cut to 20 KB, and the task tells the agent so. The task also says how many images the issue has, and that the agent cannot see them. |
|
|
278
|
+
| The state file is lost or unreadable | An unreadable file is set aside, never deleted, and the start says where it went (Q606). Each claim comment names its branch, so the watcher picks up its pull requests, and anything waiting for a person, without running anything again. |
|
|
279
|
+
| CI never finishes (a stuck job) | After 2 hours pending we notify once, and keep watching. |
|
|
280
|
+
| The repo has no CI | The PR waits for review. Nothing is assumed passed. |
|
|
281
|
+
|
|
282
|
+
### The agent
|
|
283
|
+
|
|
284
|
+
| what goes wrong | what we do |
|
|
285
|
+
|---|---|
|
|
286
|
+
| The agent CLI isn't installed | `start` refuses. |
|
|
287
|
+
| The agent is `claude` and has no `hivecode` MCP server (`setup` never ran on this machine), or has one that does not connect | `start` (and `--dry-run`) refuses (Q602) with `npx -y hivecode-mcp@latest setup`, after asking `claude mcp get hivecode`, which is read-only and spends no tokens. Without it the first run fails only after the user has paid for it. `claude` not answering in 60 s is said ("could not check"), never passed. `--skip-agent-check` is for a server set up under another name. |
|
|
288
|
+
| The agent command passes `--allowedTools` without `mcp__hivecode` | `start` refuses (Q602): in `-p` mode the hive tools would be denied, the same paid-for failure. |
|
|
289
|
+
| Any other agent CLI (Codex, Gemini) | `start` says it did not check it, never that it passed. |
|
|
290
|
+
| Logged out, usage limit, bad API key | The run fails fast. We retry once, after 15 minutes. A second failure in a row sends the issue to needs-human, with the agent's last lines in the comment and the notification. We never retry in a tight loop. |
|
|
291
|
+
| Codex refuses to start outside a git repository | A room's folder is deliberately not a git checkout. Its command needs `--skip-git-repo-check` (see "Which agents"). |
|
|
292
|
+
| The agent never joins its room (Hivecode isn't set up for that agent CLI) | Said as exactly that, with the setup command. Never reported as "no changes". |
|
|
293
|
+
| It runs forever: stuck, or waiting for a permission prompt in headless mode | A time limit per run (`--max-minutes`, default 40). We kill the whole process tree, push nothing, keep its folder for inspection, and mark the issue needs-human. |
|
|
294
|
+
| It finishes without changing anything | On a first run: no PR. We comment with its own last words and mark the issue needs-human. On a review run, a question answered needs no change: its answer is posted on the PR. |
|
|
295
|
+
| It has a question | Nobody answers during a run, and the task says so. It writes `BLOCKED: <question>` and stops. We post the question on the issue and notify. A reply from someone with write access starts the next run. |
|
|
296
|
+
| Its last edit didn't reach the room before it exited | Before landing, we reconnect its folder, under its own identity, to send anything still pending. Landing refuses to land part of a room (Q507). |
|
|
297
|
+
| It says the tests pass and they don't | With `--test`, we run them ourselves. A failure becomes the next run's task. Without `--test`, the PR body says the result is the agent's report, not ours. |
|
|
298
|
+
| The tester says nothing usable: no VERDICT, or "mostly passes" | Only `VERDICT: PASS` or `VERDICT: FAIL` counts. Anything else is a failed run, never a pass. It is retried once after 15 minutes, then goes to a person. |
|
|
299
|
+
| The tester fails the builder's work again and again | After three FAILs in a row it goes to a person, with the tester's last report. The run caps apply as well. |
|
|
300
|
+
| The tester edits the implementation, not just tests | It is told not to. If it does, the PR names those files under "Checked by", so a reviewer reads them with care. |
|
|
301
|
+
| The tester passes broken code | A PASS is the tester's word. The --test gate, then CI, still run after it, and a person reviews the PR. |
|
|
302
|
+
| It edits `.github/workflows/` | Refused unless `--allow-workflow-changes` is set. An agent misled by an issue could write a workflow that leaks the repo's secrets when CI runs. |
|
|
303
|
+
| It writes a key or token into a file | The room never carries a file with a key in it (hive-secrets.js), so the landing doesn't either. We also scan everything we post on GitHub. |
|
|
304
|
+
| A CI fix loop that never converges (a flaky test) | `--max-runs` per issue (default 6) and per day (default 20). If the same checks fail twice in a row, it goes to needs-human. |
|
|
305
|
+
| It pushes or opens a PR itself, bypassing the watcher | The task tells it not to. If it does anyway, nothing it pushed is overwritten: our push is refused, and the issue goes to a person. |
|
|
306
|
+
| It does damage outside the repo | On the user's own machine, an agent can do anything the user can. We say so plainly. To isolate it, run the watcher in a container or VM. |
|
|
307
|
+
| Prompt injection in an issue or a comment | Work starts only from a label someone with push access added. Only comments from people with write access are forwarded, checked against GitHub's permission for each person, not just their badge. The task quotes the issue as data from someone else. Agents can't merge, and a person reviews every PR. |
|
|
308
|
+
|
|
309
|
+
### The room and the relay
|
|
310
|
+
|
|
311
|
+
| what goes wrong | what we do |
|
|
312
|
+
|---|---|
|
|
313
|
+
| The relay is unreachable, or cold-starting (about 50 s on Render free) | The run doesn't start. We retry, and status says why. |
|
|
314
|
+
| The relay restarts mid-run and loses the room | The agent's folder still has its files, and its server refills the room when it reconnects. Landing checks that every file arrived (Q507). Worst case, we redo the run from the branch. |
|
|
315
|
+
| The public relay holds the code | Room ids are random (104 bits) and never posted on GitHub. `start` warns once when the repo is private and the relay is ours. Recommended: run your own relay (`npx hivecode-relay`). |
|
|
316
|
+
| A repo too big for a room | Rooms skip binaries and files over 1 MB, and agents on the watcher's machine fill those in from git. Past 5,000 files on the public relay, `start` refuses (Q608) and offers two ways out: your own relay, or `--allow-large`. |
|
|
317
|
+
|
|
318
|
+
### The machine
|
|
319
|
+
|
|
320
|
+
| what goes wrong | what we do |
|
|
321
|
+
|---|---|
|
|
322
|
+
| The laptop sleeps | Everything pauses. On wake we push each deadline back by the time asleep, so a sleeping run is not killed for being slow. For 24/7, run on a machine that stays on. |
|
|
323
|
+
| The watcher crashes, or Ctrl+C | It kills its agents' process trees on the way out. On restart, a run marked running whose process is gone counts as a failed run and is retried. |
|
|
324
|
+
| Windows | Agent CLIs are `.cmd` shims, so we start them through the shell. The prompt goes on stdin, never on the command line, so no quoting can break it. Process trees are killed with `taskkill /T`. |
|
|
325
|
+
| git asks for a password, or a credential manager opens a login window, and nobody is there to answer | Git is never allowed to prompt (`GIT_TERMINAL_PROMPT=0`, `GCM_INTERACTIVE=never`), so it fails at once instead of hanging. The error says to run `gh auth setup-git`, and the issue goes to a person rather than retrying every two minutes. |
|
|
326
|
+
| The home folder is itself a git repository, and `start` is run outside the project | `start` says exactly that, instead of a puzzling "origin (none)". |
|
|
327
|
+
| The repo has its own git hooks (husky, lefthook, a tool's post-checkout hook) | Hivecode's own scratch worktrees run without them: landing, the catch-up merge and the test gate. A hook that failed there made landing fail although git had done its job, and others run installs in a folder about to be deleted. The developer's checkout and every push keep their hooks. |
|
|
328
|
+
| The disk fills with room folders | Finished issues' folders are removed. Only the last failed run's folder is kept. |
|
|
329
|
+
|
|
330
|
+
### People
|
|
331
|
+
|
|
332
|
+
| what goes wrong | what we do |
|
|
333
|
+
|---|---|
|
|
334
|
+
| They comment while a run is going | It waits for the next run. One run per issue at a time. |
|
|
335
|
+
| They merge while a fix run is going | We kill the run, push nothing, and finish. |
|
|
336
|
+
| They want everything stopped | Remove the label, comment `/hivecode stop`, or Ctrl+C the watcher. |
|
|
337
|
+
| Notifications become noise | One per change of state, never one per comment. |
|
|
338
|
+
| They write "thanks" or "LGTM" on the PR | Nothing runs. Only reviews, inline comments, and comments starting with `/hivecode` go to the agent. |
|
|
339
|
+
| They can't approve the PR (it's theirs, under branch protection) | Said in the docs. The GitHub App fixes it. |
|
|
340
|
+
| A squash merge | GitHub keeps co-authors in the squash commit. The per-agent commits stay visible in the PR. |
|
|
341
|
+
|
|
342
|
+
### When real users arrive
|
|
343
|
+
|
|
344
|
+
| what goes wrong | what we do |
|
|
345
|
+
|---|---|
|
|
346
|
+
| A stranger's private code on our public relay | The warning above, plus `--relay` in the first line of the docs. |
|
|
347
|
+
| Their tokens get spent without them | Runs only start from a label. Every run is capped and counted, and `github status` shows today's runs. |
|
|
348
|
+
| A support question | Every refusal has a Q-code and the exact command that fixes it. |
|
|
349
|
+
| Mixed versions | The agent's own Hivecode must know branch rooms (`hive_join` with `branch`). Landing needs signed receipts, which every such runtime has. |
|
|
350
|
+
| Mac, Linux and Windows | The tests run on all three, through the existing Mac/Linux workflow. |
|
|
351
|
+
|
|
352
|
+
## Defaults
|
|
353
|
+
|
|
354
|
+
| setting | default |
|
|
355
|
+
|---|---|
|
|
356
|
+
| `--label` | `hivecode` |
|
|
357
|
+
| `--every` | 60 s |
|
|
358
|
+
| `--max-parallel` | 1 issue |
|
|
359
|
+
| `--max-minutes` | 40 per run |
|
|
360
|
+
| `--max-runs` | 6 per issue, 20 per day |
|
|
361
|
+
| `--relay` | the public relay; self-hosted recommended for private code |
|
|
362
|
+
| `--test` | off; the PR says the test result is the agent's report |
|
|
363
|
+
| `--repo` | the folder it is started in |
|
|
364
|
+
| `--dry-run` | off |
|
|
365
|
+
| `--slack-channel` | off; the token comes from `SLACK_BOT_TOKEN` |
|
|
366
|
+
|
|
367
|
+
## Build order
|
|
368
|
+
|
|
369
|
+
All built on 13 Oct 2026:
|
|
370
|
+
1. The watcher core: claim, run, land, PR, with caps and state.
|
|
371
|
+
2. The loop: CI results and trusted comments become the next run.
|
|
372
|
+
3. Kill switches and needs-human.
|
|
373
|
+
4. Notifications.
|
|
374
|
+
5. `github status`.
|
|
375
|
+
6. Docs, plus this file kept true.
|
|
376
|
+
|
|
377
|
+
## How it is tested
|
|
378
|
+
|
|
379
|
+
- `tests/github-watcher-test.mjs` runs everything for real except GitHub and the agent: a local
|
|
380
|
+
relay, a real git repo with a local `origin`, a fake GitHub inside the test, and a fake agent that
|
|
381
|
+
joins its room through the real MCP server code. It spends no tokens and touches no real repo.
|
|
382
|
+
- `tests/github-cli-test.mjs` checks what a stranger meets first: each refusal and its fix, and the
|
|
383
|
+
dry run, both on a fresh clone and on one a watcher has worked in.
|
|
384
|
+
- `scripts/github-mutants.mjs` removes each important defence in turn, and its check has to go red.
|
|
385
|
+
A defence whose check stays green is not covered, whatever the test claims.
|
|
386
|
+
|
|
387
|
+
## Not in this version
|
|
388
|
+
|
|
389
|
+
- More than one builder working the same issue at once. The tester runs after the builder, not
|
|
390
|
+
beside it.
|
|
391
|
+
- The GitHub App: bot identity, webhooks, Marketplace. It needs Ganesh's account.
|
|
392
|
+
- Agents resolving merge conflicts.
|
|
393
|
+
- One watcher for several repos.
|
|
394
|
+
- Always-on hosting, on a VM or Maritime. The watcher is the piece that would run there.
|