> ## Documentation Index
> Fetch the complete documentation index at: https://kowshik-93.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Monorepo

> One git repo, several independently-testable packages — one branch and one PR, but per-package grounding, tests, and verify evidence.

## When you need this

Skip this page entirely if your repo isn't a workspace of multiple packages — leave `packages: []`
and everything works exactly as described elsewhere in these docs.

Read on if the repo shipflow runs in (or any repo listed under `repos:` in polyrepo) is itself an
npm/pnpm/yarn workspace, an Nx or Turborepo monorepo, a Lerna repo, a Go multi-module repo, or a
.NET solution with several projects — one work item can need changes in more than one package.

<Tip>
  **Monorepo is not polyrepo.** `repos:` is for *separate git repositories*, each getting its own
  branch and PR — see [Polyrepo](/shipflow/polyrepo). `packages:` is for multiple packages **inside
  one git repository** — they share a single branch and a single PR. A repo can use both: a
  polyrepo `repos[]` entry can itself declare `packages` if that particular repo is a monorepo.
</Tip>

## The core idea

**Packages never get their own branch or PR.** Only `repos` causes that fan-out. `packages` only
changes three things: `feature-context`/`feature-plan` ground and assign tasks per package,
`feature-tests` runs each touched package's own test command, and `feature-verify` grades AC
evidence per package — all within the **one** diff and **one** PR the repo already has.

## Configuring `packages`

In `shipflow.config.md`:

```yaml theme={null}
packages:
  - name: web                       # short id used in grounding, plan, and verify output
    path: packages/web              # path within THIS repo — not a separate checkout
    tests:
      framework: vitest
      run_command: "pnpm --filter web test"
  - name: api
    path: packages/api
    tests:
      framework: jest
      run_command: "pnpm --filter api test"
```

Each entry needs a `name` (used in grounding, plan, and verify output — not branches, since there
are none per package), a `path` relative to the repo root, and an optional `tests` override for
when packages use different frameworks or need a workspace-scoped command
(`pnpm --filter <name> test`, `nx test <name>`, `turbo run test --filter=<name>`).

## Worked example

Say `AB#1234` is "show the user's subscription tier in account settings," in a pnpm-workspace
monorepo with `packages/web` and `packages/api`.

<Steps>
  <Step title="Context">
    `feature-context` normalizes two ACs (AC1: API returns `tier`, AC2: settings page displays it)
    and, since `packages` is non-empty, takes a first pass at which packages are *likely* touched —
    `api` for AC1, `web` for AC2. A first read, not a commitment, exactly like polyrepo's repo
    grounding but for packages within the one repo.
  </Step>

  <Step title="Plan">
    `feature-plan` commits to the touched set and tags every task with its package:

    | Package | Why touched                     |
    | ------- | ------------------------------- |
    | `api`   | Add `tier` to the user response |
    | `web`   | Display `tier` on settings page |

    Unlike polyrepo's repo table, there's no "gets a PR" column — packages never get one.
  </Step>

  <Step title="Implement">
    **One branch**, `feature/1234-subscription-tier`, for the whole repo. Tasks tagged `api` are
    made in `packages/api`; tasks tagged `web` in `packages/web` — same branch throughout.
  </Step>

  <Step title="Tests">
    Runs **per touched package**: `pnpm --filter api test` for the API change, `pnpm --filter web
            test` for the UI change — both on the same branch, reported separately.
  </Step>

  <Step title="Verify">
    Aggregates **per package** within the **one** diff: AC1 is MET only if `packages/api`'s code +
    test satisfy it; AC2 only if `packages/web`'s do. If `api`'s change lands but `web`'s doesn't,
    the item is **NOT READY** — same aggregation rule as polyrepo, just without a second branch.
  </Step>

  <Step title="PR">
    Opens exactly **one PR** for the repo. Its AC checklist may note `AC1 — packages/api`, `AC2 —
            packages/web` for the reviewer's benefit, but there is only ever one PR regardless of how many
    packages were touched.
  </Step>
</Steps>

## What changes vs. a single package

|              | Single package        | Monorepo                                      |
| ------------ | --------------------- | --------------------------------------------- |
| Branches     | one                   | still one — packages never add branches       |
| PRs          | one                   | still one — packages never add PRs            |
| Test runs    | one command           | one command **per touched package**           |
| AC grading   | per-file evidence     | per-file evidence, tagged with owning package |
| `state.json` | one test-result entry | one test-result entry **per touched package** |

## Combining with polyrepo

If a polyrepo `repos[]` entry is itself a monorepo, set `packages` on that entry instead of at the
top level:

```yaml theme={null}
repos:
  - name: platform
    path: ../platform
    host: github
    base: main
    packages:
      - name: web
        path: packages/web
      - name: api
        path: packages/api
```

`platform` still gets exactly one branch and one PR (per the polyrepo rule); its two packages are
graded separately within that one PR (per the monorepo rule). The two mechanisms compose without
special-casing — repo-level fan-out and package-level grounding are independent.
