Trunk-based
View as markdownTrunk-based development keeps a single always-releasable trunk
(main) and merges small, short-lived branches into it as fast as they go
green. There's no long-lived integration branch and no drawn-out review
column. Work goes from in progress to merged the moment checks pass.
In Shelbi this is the feature-branch model
with the Review handoff collapsed: the merge action moves onto the
InProgress → Done edge. A workflow with no handoff-category status
has nothing to hand finished work to, so when the developer writes its
ready marker the hub auto-advances the card along that merge edge and
merges the branch right away. This is the same path the shipped
subtask workflow uses.
Zen Mode is not consulted on this path, and
neither are zen.checks: the whole point is to land finished work without
an accept step.
The board
No Review column. An issue branch is cut off main at
In Progress and squash-merged straight back into main at Done,
the moment the developer marks it done.
The workflow
Trunk-based reuses the shipped status catalog
(workflows/statuses.yaml). It just leaves the review status out of the
flow. Identity (name, category) stays in the catalog; the workflow
references statuses by id and adds only owner and agent::
# workflows/trunk.yaml — reference-only (identity lives in statuses.yaml)
name: trunk
description: Trunk-based — short-lived branches, merge to main when done.
git:
base_branch: main
branch: '{{github_user}}/{{id}}' # e.g. you/t-065, same as the shipped task workflow
statuses:
- { id: backlog, owner: user, agent: orchestrator }
- { id: todo, owner: agent, agent: orchestrator }
- { id: in-progress, owner: agent, agent: developer }
- { id: done, owner: user }
- { id: canceled, owner: user }
initial_status: backlog
transitions:
- from: in-progress
to: done
actions: [push_branch, merge, delete_branch]
- from: in-progress
to: canceled
actions: [delete_branch]The single in-progress → done transition does the whole cycle. When the
developer writes its ready marker, the hub checks the worktree is clean and
the branch has commits, rebases the branch onto main, pushes it, and runs
merge before it moves the card to Done, so a failed merge leaves the
card in In Progress instead of marking unmerged work done. Then the edge's
remaining actions run (delete_branch). No PR is opened: with no open PR
for the branch, merge integrates it hub-side and pushes main. There is
no handoff-category status because there's no separate review stage.
The squash comes from the project's git.merge_strategy (squash by
default). The merge action always uses the project setting, so a
merge_strategy in a workflow's git: block has no effect on it.
Orchestrator adjustments
None are needed, and none would help: the merge happens in the hub as soon as the ready marker lands, so orchestrator rules and Zen merge conditions never get a chance to hold the card. The gate is whatever the developer does before it marks the work done, so put "run the build and tests, and only write the ready marker when they pass" in the developer agent's instructions.
If you want a green-checks gate before anything lands on main, keep a
review (handoff) status between In Progress and Done, as the
feature-branch model
does, and turn on Zen Mode so it can accept
review → done for you once its checks pass.
Keep branches short. If a card sits in InProgress long enough to drift
from main, prefer restacking or re-cutting it over a big catch-up merge.
That's the discipline trunk-based trades the review column for.
See also
- Feature-branch — the review-gated version of the same branch-per-issue shape.
- Zen Mode — the confidence bar and the
zen.checksthat gate areview → doneaccept when you want one. - Workflows: the subtask workflow: the shipped handoff-less workflow that merges the same way.