Feature-branch (GitHub-flow)

View as markdown

Feature-branch (a.k.a. GitHub-flow) is the simplest durable model: main is always deployable, every task cuts a short branch off it, opens a pull request, and merges back. There are no long-lived integration branches. The PR is the integration point.

This is the model Shelbi's shipped task workflow already implements, so this guide doubles as a full annotation of the shipped default. Read it first; the other guides are described as deltas from this one.

The board

you@hub — webapp
Tasks · webapp 8 total Workflow: All ▾ Workspace: All ▾ BACKLOG (2) TO DO (2) IN PROGRESS (1) REVIEW (1) DONE (2) Rework onboarding Add ratelimit to API Wire up OAuth flow Cache warm-up on Ship dark-mode copy ⎇ shelbi/wire-up-oaut…cold start toggle ⎇ shelbi/cache-warm-u… Fix mobile nav Audit image sizes overlap Migrate to Postgres 16
h/l col j/k row open n new f filter r refresh

Each card's branch is cut off main when it enters In Progress, is pushed and PR'd on the way to Review, and squash-merged back into main on the way to Done.

The workflow

Status identity (the stable id, the display name, and the category) lives once in workflows/statuses.yaml, the project-wide status catalog. Every workflow file then references those statuses by id and adds only what's workflow-specific (owner, and an optional agent:). The shipped catalog is the canonical six:

# workflows/statuses.yaml — the status catalog, shared by every workflow.
statuses:
  - { id: backlog,     name: Backlog,     category: backlog }
  - { id: todo,        name: Todo,        category: ready }
  - { id: in-progress, name: In Progress, category: active }
  - { id: review,      name: Review,      category: handoff }
  - { id: done,        name: Done,        category: done }
  - { id: canceled,    name: Canceled,    category: archived }

The default workflow references them by id. No name: or category: is repeated here (the loader rejects a workflow file that does):

# workflows/default.yaml
name: default
description: Feature-branch flow — branch per task off main, PR, merge.
 
# Inherits the project's base_branch: main and merge_strategy from
# project.yaml. A git: block here would only be needed to override them.
 
statuses:
  - { id: backlog,     owner: user,  agent: orchestrator }
  - { id: todo,        owner: agent, agent: orchestrator }
  - { id: in-progress, owner: agent, agent: developer }
  - { id: review,      owner: user,  agent: orchestrator }
  - { id: done,        owner: user }
  - { id: canceled,    owner: user }
 
initial_status: backlog
 
transitions:
  - from: in-progress
    to: review
    actions: [push_branch, open_pr]      # push the task branch, open a PR into main
 
  - from: review
    to: done
    actions: [merge, delete_branch]      # squash-merge the PR, delete the branch
 
  - from: in-progress
    to: canceled
    actions: [close_pr, delete_branch]
 
  - from: review
    to: canceled
    actions: [close_pr, delete_branch]

Nothing here overrides the project git defaults, so branches cut off main and merges land back on main. The open_pr action opens the PR with main as its base because no transition declares a target:. The user-owned review status still names agent: orchestrator. That's what lets Zen Mode land the merge without you.

Orchestrator adjustments

None. This is the shape the shipped orchestrator prompt already assumes: triage into Backlog, dispatch Todo, hand off to Review on the review marker, and leave the Review → Done accept to you. If you turn on Zen Mode, the merge on Review → Done is what the confidence bar gates.

See also

  • Workflows — the full schema and the lifecycle walkthrough this board follows.
  • Trunk-based — the same model with the Review gate collapsed and auto-merge turned on.
  • Author a custom Shelbi workflow — start here when a routing or reporting tweak is worth encoding.