Let the agent set the merge commit title, defaulting to the task title
This commit is contained in:
+4
-2
@@ -21,9 +21,11 @@ Schema changes are the `migrations` slice in `internal/store/store.go`: named en
|
||||
|
||||
A task ends `merged` or `discarded`; either way its sessions are stopped, its worktree and branch are removed, its `open` inbox items become `dismissed` (resolved by whoever closed it), and its record and events remain. `GET /api/tasks/{id}/unmerged` reports what would be lost or merged: commits on the branch that aren't on the default branch, and files, lines and uncommitted paths that differ from the merge base. The UI shows it in the confirm dialog of both buttons, which are disabled while the task's session is `running` or `queued`.
|
||||
|
||||
`POST /api/tasks/{id}/merge-in` (the transcript's **Merge main in** button, labelled with the default branch) brings the default branch into the task branch through the agent: it sends `mergeInPrompt` (`internal/agents/mergein.go`) as a `byre` message to the task's session, or starts a session with it when the task has none. The prompt has the agent run `git merge --no-ff --no-commit`, resolve conflicts, regenerate generated files rather than hand-merging them, check the build and tests, and leave the merge uncommitted; byre's end-of-turn commit concludes it as a merge commit. It is refused (409) while a session is `running` or `queued`.
|
||||
`POST /api/tasks/{id}/merge-in` (the transcript's **Merge main in** button, labelled with the default branch) brings the default branch into the task branch through the agent: it sends `mergeInPrompt` (`internal/agents/mergein.go`) as a `byre` message to the task's session, or starts a session with it when the task has none. The prompt has the agent run `git merge --no-ff --no-commit`, resolve conflicts, regenerate generated files rather than hand-merging them, check the build and tests, and leave the merge uncommitted; byre's end-of-turn commit concludes it as a merge commit. The prompt ends by showing the task's current merge title and asking the agent to set a better one with `set_merge_title` if it no longer describes all the work on the branch. It is refused (409) while a session is `running` or `queued`.
|
||||
|
||||
`POST /api/tasks/{id}/merge` starts the same turn and records, in memory, that the task is to be merged by the requesting user, who must have a git identity (400 otherwise). When that turn ends normally (not interrupted, not an error), byre squashes the worktree, now containing the default branch, onto it with `git merge-tree --merge-base`, makes one commit with `git commit-tree` authored and committed by the merging user, runs `git merge --ff-only` in the project's checkout (which must have the default branch checked out), then closes the task. The commit message is the task title. Nothing is pushed. When the merge changes nothing, no commit is made. If the squash fails, for example because the default branch moved again during the turn, byre files an error in the inbox and the task stays active. An interrupted or failed turn, or a byre restart during it, leaves the task active without squashing. `POST /api/tasks/{id}/discard` removes everything without merging.
|
||||
A task's `merge_title` is the title of the squash commit Merge makes. It is the task title until the agent calls the `set_merge_title` MCP tool (`internal/agents/mergein.go`), which it may do at any point: one line of at most 72 characters (`maxMergeTitle`), stored in `tasks.merge_title` (empty there means "use the title"), recorded as a `task.merge_title` event that the transcript shows as a note. Malformed titles are rejected with a corrective message, and so is a call once the task is closed. The Merge confirm dialog quotes the title the commit will get.
|
||||
|
||||
`POST /api/tasks/{id}/merge` starts the same turn and records, in memory, that the task is to be merged by the requesting user, who must have a git identity (400 otherwise). When that turn ends normally (not interrupted, not an error), byre squashes the worktree, now containing the default branch, onto it with `git merge-tree --merge-base`, makes one commit titled with the task's `merge_title` with `git commit-tree`, authored and committed by the merging user with no agent attribution, runs `git merge --ff-only` in the project's checkout (which must have the default branch checked out), then closes the task. Nothing is pushed. When the merge changes nothing, no commit is made. If the squash fails, for example because the default branch moved again during the turn, byre files an error in the inbox and the task stays active. An interrupted or failed turn, or a byre restart during it, leaves the task active without squashing. `POST /api/tasks/{id}/discard` removes everything without merging.
|
||||
|
||||
## Running as a service
|
||||
|
||||
|
||||
+4
-4
@@ -120,6 +120,7 @@ The Go server hosts an MCP server attached to every agent session.
|
||||
- `blocking: true` means the agent should end its turn; `false` means it continues with unblocked work.
|
||||
- The human's answer arrives as a structured next turn.
|
||||
- `thread_id` continues an existing inbox thread.
|
||||
- `set_merge_title(title)`: the title of the squash commit the task becomes (see "Merge cycle").
|
||||
- `request_review(scope, concerns[], profile?)`
|
||||
- `export_context(purpose)` → a handoff bundle (see "Handoff bundles").
|
||||
- `spawn_stages(stages[])` and `collect(stage_ids[])` for just-in-time fan-out and fan-in (see "Workflows").
|
||||
@@ -337,7 +338,7 @@ A task can go through many merge cycles before completion. Merges happen only at
|
||||
- Author: the human who confirmed the merge.
|
||||
- Co-author trailers: other humans who participated in the task since the last merge cycle (resolved inbox items, messaged agents, triggered forks).
|
||||
- No agent attribution.
|
||||
- Message: drafted by an agent from the task's turn summaries since the last merge; the human edits before confirming.
|
||||
- Message: the task's merge title, which starts as the task title and which the agent updates with `set_merge_title` as the work evolves; merging the default branch in asks it to check the title.
|
||||
4. Attach a git note to the squash commit (see "History").
|
||||
5. Push the default branch and the notes ref. If rejected because the remote moved, fetch and repeat from step 2.
|
||||
6. Reset the task branch to the new default-branch head. Required because squash commits make agent commits non-ancestors of the default branch; without the reset, later cycles accumulate spurious conflicts. Pre-squash history (the per-turn commits) remains available via snapshot refs.
|
||||
@@ -484,9 +485,8 @@ Record transcripts from the spike as the seed of the contract test suite.
|
||||
- **Not done:** snapshots, timeline scrubbing, terminals, file browser, previews.
|
||||
- **M3 — Second vendor and review.** Codex adapter with the same interface coverage, review profiles, review triggers, visual review output, cross-vendor review.
|
||||
- **M4 — Merging and history.** Full merge cycle with squash, authorship and co-author trailers, drafted commit messages, merge-resolution stage, git notes, task completion and archive, archive search, GitHub Issues integration.
|
||||
- **Done:** Merge and Discard replace "Complete task". Merge squashes the worktree, uncommitted files included, into one commit on the default branch, authored by the merging user, and fast-forwards the project checkout; it doesn't push, and it refuses on conflicts or while a turn is running.
|
||||
- **Next:** the squash commit message, which is the task title for now. Decided: a one-shot `claude -p` run in the task's worktree writes a one-line summary from the branch's log and diff stat, so Merge becomes a background job that reports back with a `task.merged` event or an error.
|
||||
- **Not done:** co-author trailers, merge-resolution stage, git notes, push, repeated merge cycles, archive search, GitHub Issues.
|
||||
- **Done:** Merge and Discard replace "Complete task". Merge squashes the worktree, uncommitted files included, into one commit on the default branch, authored by the merging user, and fast-forwards the project checkout; it doesn't push, and it refuses while a turn is running. Merge first has the agent merge the default branch in (also available alone as "Merge main in"), then squashes when that turn ends. The squash commit's title is the task's merge title: the task title until the agent sets another with the `set_merge_title` MCP tool, which the merge-in prompt asks it to do when the current title no longer describes the branch.
|
||||
- **Not done:** co-author trailers, human editing of the drafted message before confirming, merge-resolution stage, git notes, push, repeated merge cycles, archive search, GitHub Issues.
|
||||
- **M5 — Workflows.** Workflow definitions and storage, stages, gates, bounded loops, plan artifact, eval stages, task intake, mid-task swapping.
|
||||
- **M6 — Fan-out.** `export_context` and handoff bundles, same-vendor forks, cross-vendor handoffs, fork-and-compare, just-in-time fan-out with limits.
|
||||
- **M7 — Inbox triage.**
|
||||
|
||||
Reference in New Issue
Block a user