Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
jezweb avatar

Fork Discipline

  • 722 installs
  • 946 repo stars
  • Updated July 2, 2026
  • jezweb/claude-skills

fork-discipline is a Claude Code skill that audits whether shared platform code stays in core versus per-deployment client folders for developers who fork or white-label multi-client SaaS builds.

About

fork-discipline is a Claude Code-only Agent Skill from jezweb/claude-skills that enforces the core/client boundary in multi-client projects. The skill detects shared platform code tangled with client-specific logic, hardcoded client checks, config files that replace instead of merge, scattered client code, migration conflicts, and missing extension points. Developers reach for fork-discipline before forking or white-labeling another customer build to avoid compounding technical debt. Outputs include a boundary map, violation report, refactoring plan, optional FORK.md documentation, and restructuring scripts.

  • Maps core vs client layout: shared `src/`, default `config/`, per-deployment `clients/client-name/`
  • Detects hardcoded client checks, replace-not-merge config, scattered client code, and migration conflicts
  • Produces a boundary map, violation report, and refactoring plan
  • Optionally generates FORK.md and restructuring scripts
  • Triggers on fork discipline, platform audit, fork test, and refactor for multi-client

Fork Discipline by the numbers

  • 722 all-time installs (skills.sh)
  • +31 installs in the week ending Jul 25, 2026 (Skillselion tracking)
  • Ranked #185 of 1,356 Code Review & Quality skills by installs in the Skillselion catalog
  • Security screen: LOW risk (skills.sh audit)
  • Data as of Jul 31, 2026 (Skillselion catalog sync)
npx skills add https://github.com/jezweb/claude-skills --skill fork-discipline

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs722
repo stars946
Security audit3 / 3 scanners passed
Last updatedJuly 2, 2026
Repositoryjezweb/claude-skills

How do you separate core from client code?

Audit whether shared platform code stays in core versus per-deployment client folders before you fork or white-label another customer build.

Who is it for?

Developers maintaining multi-client or white-label SaaS platforms who need a core/client boundary audit before the next customer fork.

Skip if: Single-tenant apps with no fork plans, greenfield projects, or teams without shared platform plus per-client deployment folders.

When should I use this skill?

The user mentions fork discipline, core or client boundary, platform audit, client separation, or refactoring for multi-client deployments.

What you get

Boundary map, violation report, refactoring plan, optional FORK.md, and restructuring scripts for multi-client separation.

  • Boundary map
  • Violation report
  • FORK.md documentation

Files

SKILL.mdMarkdownGitHub ↗

Fork Discipline

Audit the core/client boundary in multi-client codebases. Every multi-client project should have a clean separation between shared platform code (core) and per-deployment code (client). This skill finds where that boundary is blurred and shows you how to fix it.

The Principle

project/
  src/            ← CORE: shared platform code. Never modified per client.
  config/         ← DEFAULTS: base config, feature flags, sensible defaults.
  clients/
    client-name/  ← CLIENT: everything that varies per deployment.
      config      ← overrides merged over defaults
      content     ← seed data, KB articles, templates
      schema      ← domain tables, migrations (numbered 0100+)
      custom/     ← bespoke features (routes, pages, tools)

The fork test: Before modifying any file, ask "is this core or client?" If you can't tell, the boundary isn't clean enough.

When to Use

  • Before adding a second or third client to an existing project
  • After a project has grown organically and the boundaries are fuzzy
  • When you notice if (client === 'acme') checks creeping into shared code
  • Before a major refactor to understand what's actually shared vs specific
  • When onboarding a new developer who needs to understand the architecture
  • Periodic health check on multi-client projects

Modes

ModeTriggerWhat it produces
audit"fork discipline", "check the boundary"Boundary map + violation report
document"write FORK.md", "document the boundary"FORK.md file for the project
refactor"clean up the fork", "enforce the boundary"Refactoring plan + migration scripts

Default: audit

---

Audit Mode

Step 1: Detect Project Type

Determine if this is a multi-client project and what pattern it uses:

SignalPattern
clients/ or tenants/ directoryExplicit multi-client
Multiple config files with client namesConfig-driven multi-client
packages/ with shared + per-client packagesMonorepo multi-client
Environment variables like CLIENT_NAME or TENANT_IDRuntime multi-client
Only one deployment, no client dirsSingle-client (may be heading multi-client)

If single-client: check if the project CLAUDE.md or codebase suggests it will become multi-client. If so, audit for readiness. If genuinely single-client forever, this skill isn't needed.

Step 2: Map the Boundary

Build a boundary map by scanning the codebase:

CORE (shared by all clients):
  src/server/          → API routes, middleware, auth
  src/client/          → React components, hooks, pages
  src/db/schema.ts     → Shared database schema
  migrations/0001-0050 → Core migrations

CLIENT (per-deployment):
  clients/acme/config.ts    → Client overrides
  clients/acme/kb/          → Knowledge base articles
  clients/acme/seed.sql     → Seed data
  migrations/0100+          → Client schema extensions

BLURRED (needs attention):
  src/server/routes/acme-custom.ts  → Client code in core!
  src/config/defaults.ts line 47    → Hardcoded client domain

Step 3: Find Violations

Scan for these specific anti-patterns:

Client Names in Core Code
# Search for hardcoded client identifiers in shared code
grep -rn "acme\|smith\|client_name_here" src/ --include="*.ts" --include="*.tsx"

# Search for client-specific conditionals
grep -rn "if.*client.*===\|switch.*client\|case.*['\"]acme" src/ --include="*.ts" --include="*.tsx"

# Search for environment-based client checks in shared code
grep -rn "CLIENT_NAME\|TENANT_ID\|process.env.*CLIENT" src/ --include="*.ts" --include="*.tsx"

Severity: High. Every hardcoded client check in core code means the next client requires modifying shared code.

Config Replacement Instead of Merge

Check if client configs replace entire files or merge over defaults:

// BAD — client config is a complete replacement
// clients/acme/config.ts
export default {
  theme: { primary: '#1E40AF' },
  features: { emailOutbox: true },
  // Missing all other defaults — they're lost
}

// GOOD — client config is a delta merged over defaults
// clients/acme/config.ts
export default {
  theme: { primary: '#1E40AF' },  // Only overrides what's different
}
// config/defaults.ts has everything else

Look for: client config files that are suspiciously large (close to the size of the defaults file), or client configs that define fields the defaults already handle.

Severity: Medium. Stale client configs miss new defaults and features.

Scattered Client Code

Check if client-specific code lives outside the client directory:

# Files with client names in their path but inside src/
find src/ -name "*acme*" -o -name "*smith*" -o -name "*client-name*"

# Routes or pages that serve a single client
grep -rn "// only for\|// acme only\|// client-specific" src/ --include="*.ts" --include="*.tsx"

Severity: High. Client code in src/ means core is not truly shared.

Missing Extension Points

Check if core has mechanisms for client customisation without modification:

Extension pointHow to checkWhat it enables
Config mergeDoes config/ have a merge function?Client overrides without replacing
Dynamic importsDoes core look for clients/{name}/custom/?Client-specific routes/pages
Feature flagsAre features toggled by config, not code?Enable/disable per client
Theme tokensAre colours/styles in variables, not hardcoded?Visual customisation
Content injectionCan clients provide seed data, templates?Per-client content
Hook/event systemCan clients extend behaviour without patching?Custom business logic

Severity: Medium. Missing extension points force client code into core.

Migration Number Conflicts
# List all migration files with their numbers
ls migrations/ | sort | head -20

# Check if client migrations are in the reserved ranges
# Core: 0001-0099, Client domain: 0100-0199, Client custom: 0200+

Severity: Low until it causes a conflict, then Critical.

Feature Flags vs Client Checks
// BAD — client name check
if (clientName === 'acme') {
  showEmailOutbox = true;
}

// GOOD — feature flag in config
if (config.features.emailOutbox) {
  showEmailOutbox = true;
}

Search for patterns where behaviour branches on client identity instead of configuration.

Step 4: Produce the Report

Write to .jez/artifacts/fork-discipline-audit.md:

# Fork Discipline Audit: [Project Name]
**Date**: YYYY-MM-DD
**Pattern**: [explicit multi-client / config-driven / monorepo / single-heading-multi]
**Clients**: [list of client deployments]

## Boundary Map

### Core (shared)
| Path | Purpose | Clean? |
|------|---------|--------|
| src/server/ | API routes | Yes / No — [issue] |

### Client (per-deployment)
| Client | Config | Content | Schema | Custom |
|--------|--------|---------|--------|--------|
| acme | config.ts | kb/ | 0100-0120 | custom/routes/ |

### Blurred (needs attention)
| Path | Problem | Suggested fix |
|------|---------|--------------|
| src/routes/acme-custom.ts | Client code in core | Move to clients/acme/custom/ |

## Violations

### High Severity
[List with file:line, description, fix]

### Medium Severity
[List with file:line, description, fix]

### Low Severity
[List]

## Extension Points
| Point | Present? | Notes |
|-------|----------|-------|
| Config merge | Yes/No | |
| Dynamic imports | Yes/No | |
| Feature flags | Yes/No | |

## Health Score
[1-10] — [explanation]

## Top 3 Recommendations
1. [Highest impact fix]
2. [Second priority]
3. [Third priority]

---

Document Mode

Generate a FORK.md for the project root that documents the boundary:

# Fork Discipline

## Architecture

This project serves multiple clients from a shared codebase.

### What's Core (don't modify per client)
[List of directories and their purpose]

### What's Client (varies per deployment)
[Client directory structure with explanation]

### How to Add a New Client
1. Copy `clients/_template/` to `clients/new-client/`
2. Edit `config.ts` with client overrides
3. Add seed data to `content/`
4. Create migrations numbered 0100+
5. Deploy with `CLIENT=new-client wrangler deploy`

### The Fork Test
Before modifying any file: is this core or client?
- Core → change in `src/`, all clients benefit
- Client → change in `clients/name/`, no other client affected
- Can't tell → the boundary needs fixing first

### Migration Numbering
| Range | Owner |
|-------|-------|
| 0001-0099 | Core platform |
| 0100-0199 | Client domain schema |
| 0200+ | Client custom features |

### Config Merge Pattern
Client configs are shallow-merged over defaults:
[Show the actual merge code from the project]

---

Refactor Mode

After an audit, generate the concrete steps to enforce the boundary:

1. Move Client Code Out of Core

For each violation where client code lives in src/:

# Create client directory if it doesn't exist
mkdir -p clients/acme/custom/routes

# Move the file
git mv src/routes/acme-custom.ts clients/acme/custom/routes/

# Update imports in core to use dynamic discovery

2. Replace Client Checks with Feature Flags

For each if (client === ...) in core:

// Before (in src/)
if (clientName === 'acme') {
  app.route('/email-outbox', emailRoutes);
}

// After (in src/) — feature flag
if (config.features.emailOutbox) {
  app.route('/email-outbox', emailRoutes);
}

// After (in clients/acme/config.ts) — client enables it
export default {
  features: { emailOutbox: true }
}

3. Implement Config Merge

If the project replaces configs instead of merging:

// config/resolve.ts
import defaults from './defaults';

export function resolveConfig(clientConfig: Partial<Config>): Config {
  return {
    ...defaults,
    ...clientConfig,
    features: { ...defaults.features, ...clientConfig.features },
    theme: { ...defaults.theme, ...clientConfig.theme },
  };
}

4. Add Extension Point for Custom Routes

If clients need custom routes but currently modify core:

// src/server/index.ts — auto-discover client routes
const clientRoutes = await import(`../../clients/${clientName}/custom/routes`)
  .catch(() => null);
if (clientRoutes?.default) {
  app.route('/custom', clientRoutes.default);
}

5. Generate the Refactoring Script

Write a script to .jez/scripts/fork-refactor.sh that:

  • Creates the client directory structure
  • Moves identified files
  • Updates import paths
  • Generates the FORK.md

---

The Right Time to Run This

Client countWhat to do
1Don't refactor. Just document the boundary (FORK.md) so you know where it is.
2Run the audit. Fix high-severity violations. Start the config merge pattern.
3+Full refactor mode. The boundary must be clean — you now have proof of what varies.

Rule 5 from the discipline: Don't abstract until client #3. With 1 client you're guessing. With 2 you're pattern-matching. With 3+ you know what actually varies.

Tips

  • Run this before adding a new client, not after
  • Config merge is the single highest-ROI refactor — do it first
  • Feature flags beat if (client) even with one client. "This is mostly the same except..." = feature flag, not fork.
  • FORK.md is for the team, not just for Claude — write it like a human will read it

Related skills

How it compares

Pick fork-discipline over generic refactor skills when the codebase has explicit core and per-deployment client folders and white-label forks are planned.

FAQ

What violations does fork-discipline detect?

fork-discipline detects hardcoded client checks, shared platform code mixed with client-specific logic, config files that replace instead of merge, scattered client folders, migration conflicts, and missing extension points in multi-client projects.

What artifacts does fork-discipline produce?

fork-discipline produces a boundary map, violation report, and refactoring plan for core versus client separation. The skill can optionally generate FORK.md documentation and restructuring scripts to guide the next customer fork.

Is Fork Discipline safe to install?

skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.

Code Review & Qualitybackenddevopsintegrations

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.