# Forking

Contributions arrive as pull requests from forks, and a review gate stands between them and main. Model the maintainer's side — triage, an automated review pass, and a human sign-off before merge.

In the **forking workflow** contributors don't push to the canonical
repository at all. They fork it, work on their own copy, and open a pull
request from the fork. The maintainer's job is a *review gate*: triage
what comes in, run it through checks, and merge only what clears sign-off.
It's the model most open-source projects run.

Shelbi models the **maintainer's side**. Because the branch lives on
someone else's fork, Shelbi doesn't cut branches or push here. Each task
carries the fork's PR branch in [`branch:`](/docs/guides/getting-started/workflows#the-branch-task-field),
and the workflow is mostly about the gate: a `handoff` sign-off status
that's `owner: user` so nothing reaches `main` without a human (or a
[Zen](/docs/concepts/zen-mode)-authorized reviewer agent) accepting it.

## The board

A fork PR lands in **Incoming**, the orchestrator triages it into scope,
the `reviewer` agent runs it through checks in **In Review**, and it waits
in **Sign-off** for a maintainer to accept before it's **Merged**.

## The statuses

The forking flow relabels the whole board, so declare its statuses (`id`
+ `name` + `category`) in the project's
[status catalog](/docs/guides/getting-started/workflows#schema) first
(`workflows/statuses.yaml`), then reference them by `id` from the workflow:

```yaml
# workflows/statuses.yaml — the forking project's status catalog.
statuses:
  - { id: incoming,  name: Incoming,  category: backlog }
  - { id: triage,    name: Triage,    category: ready }
  - { id: in-review, name: In Review, category: active }
  - { id: sign-off,  name: Sign-off,  category: handoff }
  - { id: merged,    name: Merged,    category: done }
  - { id: declined,  name: Declined,  category: archived }
```

## The workflow

```yaml
# workflows/contribution.yaml — reference-only; identity lives in statuses.yaml
name: contribution
description: Forking flow — review gate for pull requests from forks.

git:
  base_branch: main
  merge_strategy: squash               # squash external contributions into one commit

statuses:
  - { id: incoming,  owner: user }
  - { id: triage,    owner: agent, agent: orchestrator }
  - { id: in-review, owner: agent, agent: reviewer }
  - { id: sign-off,  owner: user }
  - { id: merged,    owner: user }
  - { id: declined,  owner: user }

initial_status: incoming

transitions:
  - from: in-review
    to: sign-off
    actions: [push_branch]               # push the fork branch to a review ref; no PR to open

  - from: sign-off
    to: merged
    actions: [merge]                     # squash-merge the existing fork PR into main

  - from: in-review
    to: declined
    actions: [close_pr]                  # close the PR without merging; the fork keeps its branch
```

Two side-effects that the [feature-branch](/docs/guides/understanding-workflows/feature-branch)
model uses are deliberately *absent* here:

- **No `open_pr`.** The contributor already opened the PR from their fork.
  The task just tracks it. Pre-fill `branch:` with the PR's head ref so
  `merge` and `close_pr` act on the right PR.
- **No `delete_branch`.** Shelbi can't delete a branch it doesn't own. The
  fork keeps its branch whether the PR merges or is declined.

The `in-review` status names an [`agent: reviewer`](/docs/concepts/agents)
role, an agent you author to run the untrusted contribution through the
project's checks and summarize risk before a human ever looks. The
`sign-off` status stays `owner: user`: the gate is the whole point.

## Orchestrator adjustments

The review gate needs the orchestrator to treat incoming forks as
untrusted and never to auto-accept. Encode a triage rule and a hard stop
at sign-off:

```markdown
## Routing rules — forking

- **Incoming fork PRs** are untrusted. Never dispatch a contribution to a
  workspace that holds credentials or can reach production. Route `Triage`
  cards only to sandboxed hub workspaces.
- In `Triage`, decline anything out of scope (wrong direction, duplicate,
  no linked issue) into `Declined` with a one-line reason. Promote the
  rest to `InReview` for the `reviewer` agent.

## Zen Mode — forking

The `SignOff → Merged` edge is `owner: user` and must stay a human
decision. Do **not** auto-merge contributions even when checks are green:
report "`<PR>` passed review and is ready to sign off" and wait. A green
check is necessary but not sufficient for merging someone else's code.
```

That last rule is the difference between forking and
[trunk-based](/docs/guides/understanding-workflows/trunk-based): trunk-based leans *into*
auto-merge for your own green work; forking deliberately keeps a human at
the gate for code that arrived from outside.

## See also

- [Agents](/docs/concepts/agents) — how to author the `reviewer` role the
  `InReview` status dispatches to.
- [Workflows: the `branch:` task field](/docs/guides/getting-started/workflows#the-branch-task-field)
  — pointing a task at an existing fork PR branch instead of cutting one.
- [Trunk-based](/docs/guides/understanding-workflows/trunk-based) — the opposite end of the
  auto-merge spectrum, for work you trust.
