Design Engineering
Foundations

Collaborative Repository Workflow

Work safely with designers, developers, and agents in the same repository while redesigning UI, shipping features, and keeping the app functional.

Shared repositories with designers, developers, and agents making simultaneous changes are a coordination problem. The patterns below keep the app shippable while work happens in parallel.

Why Collaboration Breaks Down

Most collaboration failures come from predictable sources:

ProblemSymptomRoot Cause
Long-lived branchesMerge hell, rebase fatigue, conflicts in every fileRedesign done as one monolithic branch over weeks
Overlapping responsibilityTwo people editing the same component for different reasonsNo ownership map or communication artifact
Agent overwritesAn AI agent refactors a file someone else is actively editingNo locking, no awareness of in-progress work
Visual-only vs. behavior-onlyA redesign PR changes CSS and business logic, making review impossibleMixed concerns in a single PR
Stale preview deploymentsPR previews don't reflect latest main, so reviewer sees broken UINo automated rebase or merge-update cycle

The patterns below address each of these.

Working Model

Vertical-Slice Redesign

Instead of a single "redesign everything" branch, break the work into vertical slices that each touch every layer but only for one concern at a time:

  1. Design tokens first — Ship the colour palette, typography scale, spacing, and shadow tokens to main before any component changes. This is a pure CSS/config PR with zero visual change to the app (tokens are defined but unused).
  2. Primitives and layout — Update the core primitive components (Button, Input, Card, Dialog) and top-level layout shell (header, sidebar, main area). These components compose everything below them.
  3. Route groups one at a time — Update the pages inside one route group (e.g. /settings/*) from old primitives to new primitives. Merge each route group independently.
  4. High-risk flows last — Payment flows, auth flows, and data-mutation-heavy pages ship last when the new system is battle-tested in lower-risk areas.

Each slice is a deployable, reviewable PR that keeps the app functional.

Vertical-slice redesign means a single PR touches multiple layers (tokens → primitives → pages) but only for one slice of the app. This keeps PRs small enough to review while ensuring each slice is actually integrated before the next one starts.

Branching Strategy

main
 └── dev                    # integration branch, always deployable
      ├── feat/blue-tokens          → dev  (token definitions only)
      ├── feat/new-primitives       → dev  (Button, Input, Card)
      ├── feat/redesign-settings    → dev  (settings route group)
      ├── feat/redesign-dashboard   → dev  (dashboard route group)
      └── fix/payment-validation    → dev  (independent feature work)
  • main — Production. Only merges from dev after verification.
  • dev — Integration branch. All feature branches merge here. Must always be deployable.
  • feat/* — Short-lived (1–3 day) feature branches. One concern per branch.
  • fix/* — Bug fixes that target dev (or main for hotfixes).

No branch lives longer than a few days. If a redesign branch exceeds one week, it is too large and should be split into smaller slices.

Git Worktrees

For very large redesigns where you need to run the old app and the new design simultaneously, use Git worktrees to check out multiple branches at once:

# Create a worktree for the redesign branch alongside your dev checkout
git worktree add ../frontendguide-redesign feat/redesign-shell

# Work on the redesign in ../frontendguide-redesign
# Keep the original checkout on dev for day-to-day work
# Each worktree gets its own node_modules and dev server

This allows running pnpm dev on two ports simultaneously — one showing the current app, one showing the redesign. It is the safest way to do side-by-side comparison without commit juggling.

Git worktrees share the same .git directory and remote tracking. Run pnpm install in each worktree separately. Do not share node_modules across worktrees as dependency versions may differ.

Feature Flags & Compatibility Layers

Route-Level Gates

For redesigning an entire section of the app, use a simple feature flag that switches between old and new implementations at the route level:

app/settings/layout.tsx
import { getFeatureFlag } from "@/lib/feature-flags";

export default async function SettingsLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const useNewDesign = await getFeatureFlag("settings-redesign");

  if (!useNewDesign) {
    return <LegacySettingsShell>{children}</LegacySettingsShell>;
  }

  return <NewSettingsShell>{children}</NewSettingsShell>;
}

This lets you ship new page implementations progressively while keeping the old routes accessible. When the new design is verified, remove the flag and delete the legacy components.

Component Compatibility Adapters

When redesigning a shared component (e.g. Button), create an adapter that maps the old API to the new one so consumers don't break:

components/ui/button.tsx
// v2 — new design with new API
interface ButtonProps {
  variant: "primary" | "secondary" | "ghost";
  size: "sm" | "md" | "lg";
  children: React.ReactNode;
}

// Export a compatibility layer that wraps v2 for v1 consumers
export function Button_v1(props: LegacyButtonProps) {
  return <Button_v2 {...mapLegacyProps(props)} />;
}

Keep the adapter as long as any consumer still uses the legacy API. Remove it when all consumers have migrated.

Adapters should be temporary — no more than two release cycles. Track remaining legacy consumers with a lint rule or deprecation warning.

Feature Flag Service

For simple flag management without external dependencies, use a file-based or environment-variable approach:

lib/feature-flags.ts
const flags: Record<string, boolean> = {
  "settings-redesign": process.env.FLAG_SETTINGS_REDESIGN === "1",
  "dashboard-redesign": process.env.FLAG_DASHBOARD_REDESIGN === "1",
  "new-nav": process.env.FLAG_NEW_NAV === "1",
};

export async function getFeatureFlag(name: string): Promise<boolean> {
  return flags[name] ?? false;
}

For production teams, use a proper flag management system (LaunchDarkly, Split, Vercel Flags) that supports gradual rollouts, A/B testing, and kill switches.

PR Slicing & Review

Split Visual from Behavioural Changes

A single pull request should not mix visual changes with data logic. Split into:

PR typeContentsReviewers
Visual redesignCSS, tokens, component props, layout onlyDesigner + design engineer
Behavior changeData fetching, state management, form logic, authEngineering lead
Content changeCopy, labels, error messagesProduct manager / content designer
InfrastructureCI/CD, dependencies, build configDevOps / platform

This makes review faster and safer — a designer does not need to audit data fetching logic, and an engineer does not need to sign off on spacing tokens.

PR Templates

Use a PR template that pre-fills the coordination context:

.github/PULL_REQUEST_TEMPLATE/redesign.md
## Description
_What part of the redesign does this PR address?_

## Slice
- [ ] Design tokens
- [ ] Primitives / layout shell
- [ ] Route group: ___
- [ ] High-risk flow

## Coordination
- [ ] This PR changes a shared component — notify `@frontend-team`
- [ ] This PR adds a feature flag — flag name: ___
- [ ] This PR has visual changes — add a preview deployment link

## Compatibility
- [ ] Backward compatible (no breaking API changes)
- [ ] Adapter layer included (legacy API mapped to new implementation)
- [ ] Breaking change — migration path documented

## Visual QA
_Paste a screenshot or preview deployment link_

Ownership Map

Maintain a lightweight ownership map so contributors know who to coordinate with:

docs/ownership-map.md
| Area | Primary | Secondary |
|---|---|---|
| Design tokens / theme | Alice | Bob |
| Component primitives | Bob | Alice |
| Settings pages | Charlie | Diana |
| Dashboard | Diana | Charlie |
| Authentication flows | Eve | Frank |
| API / data layer | Frank | Eve |
| CI / deployment | Grace | Alice |

This is not a rigid CODEOWNERS file — it is a communication tool. Update it at the start of each sprint or redesign phase.

Communication Artifacts

Redesign Risk Register

For significant redesigns, maintain a risk register that tracks what could go wrong and how each risk is mitigated:

RiskLikelihoodImpactMitigation
Design tokens break existing componentsMediumHighShip tokens before any component changes; verify with visual regression
New layout breaks responsive behaviourMediumHighResponsive review checklist; test at 320px, 768px, 1024px, 1440px
Feature flag polarity confusionLowHighClear naming convention: feature-{name}-enabled
Agent overwrites in-progress workMediumMediumAgent works only in dedicated branches; explicit README lock file

Visual QA Checklist

Before merging any redesign PR, verify:

  • Preview deployment renders correctly
  • All interactive states work (hover, focus, active, disabled)
  • Keyboard navigation follows the visual order
  • Screen reader announces new content correctly
  • Dark mode renders correctly
  • Responsive behaviour is preserved
  • Loading, empty, and error states render correctly
  • No visual regression in areas outside the PR scope

Agent Collaboration in Team Repos

When AI coding agents work in a shared repository, they introduce a new coordination challenge: the agent has no awareness of what other contributors are doing.

Agent-Safe Workflow

  1. Dedicated agent branches — Agents create branches with a consistent prefix (e.g. agent/*) that signal "AI-generated code, review required before merging."
  2. README lock file — Before asking an agent to work on a file, check docs/agent-lock.md for any "do not edit" markers placed by human contributors.
  3. Explicit scope — The agent's prompt defines the exact files it may modify and the exact change it should make. No implicit side effects.
  4. Review-only branches — Agent branches are never merged directly. A human reviews and merges (or rejects) them.
  5. Feature flag safety — Agents should gate substantial visual changes behind feature flags so the PR can be merged without affecting the live app.

Agent Lock File

docs/agent-lock.md
# Agent Lock File

Files listed here are actively being edited by a human contributor.
Agents must not modify these files until the lock is removed.

| File | Locked by | Until |
|---|---|---|
| `components/ui/button.tsx` | Alice | 2026-06-03 |
| `app/settings/page.tsx` | Bob | PR #47 merged |

Files not listed are available for agent work unless otherwise constrained by the agent's scope.

Commit Attribution

Agents should generate commits with clear attribution so humans can filter agent-generated changes during review:

git commit -m "feat: add empty state to settings panel [generated]"

Tag agent-generated commits with [generated] in the subject line. This makes it trivial to filter agent work with git log --grep='\[generated\]'.

Never merge agent-generated commits without human review. Agents can introduce subtle regressions in accessibility, performance, and styling that automated checks may not catch. A human must run the visual QA checklist before merging.

Summary

The key to collaborative repository work is keeping changes small, coordinated, and reversible:

PrinciplePractice
Slice verticallyOne concern per PR, across all layers
Ship tokens firstPure CSS/config changes before any component work
Gate with flagsFeature flags enable safe incremental deployment
Separate concerns in PRsVisual changes in one PR, behaviour changes in another
Own itOwnership map prevents overlap
Lock for agentsAgent lock file prevents overwrites
Review visuallyVisual QA checklist catches regressions
Keep branches shortNo branch lives longer than a few days

On this page