Remote Work Tools

Prerequisites

Before you begin, make sure you have the following ready:

Step 1: Code Standards in Distributed Teams

Distributed teams produce inconsistent code. One engineer uses 2-space indentation, another 4-space. One prefers functional style, another object-oriented. Without enforcement, code reviews become style arguments instead of substance discussions.

Effective code standards are:

This guide covers the toolchain for distributed teams: pre-commit hooks, linters, formatters, EditorConfig, CI enforcement, and review guidelines.

Step 2: Architecture: Local Enforcement First

The optimal flow:

  1. Engineer makes a code change
  2. Pre-commit hook runs linter, formatter, security check
  3. If checks fail, code doesn’t commit (engineer fixes locally)
  4. Code commits locally with confidence
  5. Push to remote triggers CI (which re-runs checks as final gate)
  6. Code review focuses on logic, not style

This means most standard violations are caught locally, never pushed. CI is a safety net, not the primary enforcement.

Step 3: EditorConfig: The First Layer

EditorConfig is a simple format that tells editors how to format code. Create a .editorconfig file in your repo root:

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.{js,ts,jsx,tsx}]
indent_style = space
indent_size = 2

[*.{py,pyi}]
indent_style = space
indent_size = 4

[*.{go}]
indent_style = tab

[*.md]
trim_trailing_whitespace = false

This says: “All files use UTF-8, Unix line endings, final newline. JS files use 2-space indentation. Python uses 4-space. Go uses tabs. Markdown preserves trailing whitespace.”

EditorConfig works in: VS Code (with extension), JetBrains IDEs (native), Sublime, Vim, Emacs, Notepad++.

When an engineer opens a file, their editor automatically applies these settings. No configuration needed. Indentation just works.

Setup cost: 5 minutes. Benefit: 90% of formatting differences prevented before linting.

Step 4: Prettier: Opinionated Code Formatter

Prettier is the JavaScript/TypeScript formatter. It has no configuration (by design): you use Prettier’s opinions.

Install:

npm install --save-dev prettier

Format all files:

npx prettier --write .

Add to package.json:

{
  "scripts": {
    "format": "prettier --write .",
    "format:check": "prettier --check ."
  }
}

Prettier is opinionated: 2-space indents, semicolons, double quotes, trailing commas in multiline objects. These choices are non-negotiable. No .prettierrc config needed (though you can override if truly necessary).

The power of Prettier: zero arguments about formatting style. You run prettier --write once per sprint. All code is consistently formatted. Code reviews never mention indentation again.

For distributed teams, this is critical. A Berlin engineer and a San Francisco engineer both run prettier --write before committing. Their code formats identically. No review feedback about spacing or bracket placement.

Step 5: ESLint: JavaScript Linting

ESLint catches errors: unused variables, unreachable code, type confusion, security issues.

Install:

npm install --save-dev eslint
npx eslint --init

Create .eslintrc.json:

{
  "env": {
    "node": true,
    "es2022": true
  },
  "extends": [
    "eslint:recommended",
    "next/core-web-vitals"
  ],
  "rules": {
    "no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
    "no-console": ["warn", { "allow": ["warn", "error"] }],
    "eqeqeq": ["error", "always"],
    "prefer-const": "error",
    "no-var": "error"
  }
}

Rules explained:

Run linting:

npx eslint . --fix

The --fix flag auto-fixes many issues (unused vars removed, == changed to ===). Anything it can’t fix requires manual correction.

Step 6: Pylint / Flake8: Python Linting

For Python, use Flake8 (syntax/logic errors) + Black (formatter, Python’s Prettier).

Install:

pip install flake8 black

Black format all files:

black .

Flake8 checks:

flake8 .

Create setup.cfg:

[flake8]
max-line-length = 88
extend-ignore = E203, W503

Black enforces 88-character line length, 4-space indents, double quotes. Flake8 checks for unused imports, undefined variables, complexity.

Combined: Black formats, Flake8 catches errors.

Step 7: Pre-Commit Hooks: Local Enforcement

Pre-commit hooks run before git commit. If they fail, the commit is blocked.

Install pre-commit:

pip install pre-commit

Create .pre-commit-config.yaml:

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.4.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files
        args: ['--maxkb=500']
      - id: check-merge-conflict

  - repo: https://github.com/psf/black
    rev: 23.3.0
    hooks:
      - id: black
        language_version: python3

  - repo: https://github.com/PyCQA/flake8
    rev: 6.0.0
    hooks:
      - id: flake8

  - repo: https://github.com/pre-commit/mirrors-prettier
    rev: v3.0.0
    hooks:
      - id: prettier
        types_or: [javascript, typescript, jsx, tsx, json, yaml]

  - repo: https://github.com/pre-commit/mirrors-eslint
    rev: v8.42.0
    hooks:
      - id: eslint
        types: [javascript, jsx]
        additional_dependencies: ['eslint']

Install the hooks:

pre-commit install

From now on, every git commit runs:

  1. Trailing whitespace removal
  2. Fix EOF
  3. YAML syntax check
  4. Reject files >500KB
  5. Check for merge conflict markers
  6. Black formatting (Python)
  7. Flake8 checks (Python)
  8. Prettier formatting (JS/TS/JSON/YAML)
  9. ESLint checks (JS/TS)

If any check fails, the commit is rejected. Engineer fixes the issue, stages the changes, commits again.

Example: Engineer commits with trailing whitespace:

$ git commit -m "Add user authentication"
Trim trailing whitespace.....................................................
This hook suggests to exclude these patterns from the list of files that need
to be transformed.  Edit `.pre-commit-config.yaml` to add patterns:
  file1.py
FAILED - hook id: trailing-whitespace

The hook fixed the trailing whitespace, but the commit failed. Engineer stages the fixed file and commits again:

$ git add file1.py
$ git commit -m "Add user authentication"
Trim trailing whitespace.....................................................
Check Yaml...................................................................
Black code formatter...........................................................
Flake8.......................................................................
All checks passed. [develop abc1234] Add user authentication

All checks pass, commit succeeds.

For distributed teams, this is essential: no matter your timezone or editor, code meets standards before pushing.

Step 8: CI: Final Enforcement Gate

Pre-commit hooks run locally. But if an engineer skips hooks (git commit –no-verify), code reaches remote without checks.

CI re-runs all checks on every push:

GitHub Actions .github/workflows/ci.yml:

name: CI

on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.10', '3.11']

    steps:
      - uses: actions/checkout@v3

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}

      - name: Install dependencies
        run: |
          pip install --upgrade pip
          pip install black flake8 pylint

      - name: Run Black
        run: black --check .

      - name: Run Flake8
        run: flake8 .

      - name: Run Pylint
        run: pylint $(find . -name "*.py" | grep -v venv)

  js-lint:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: Set up Node
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm ci

      - name: Run Prettier
        run: npm run format:check

      - name: Run ESLint
        run: npm run lint

      - name: Run Tests
        run: npm test

When a PR is pushed, GitHub Actions automatically:

  1. Checks out code
  2. Runs Black format check
  3. Runs Flake8 lint
  4. Runs Pylint
  5. Runs Prettier check
  6. Runs ESLint
  7. Runs tests

If any check fails, the PR is marked as failing. The PR cannot be merged until all checks pass.

This is the final gate. Even if someone skips pre-commit hooks locally, CI catches the violations.

Step 9: Distributed Team Gotchas

Timezone: When Code Is Reviewed

CI runs 24/7, but humans don’t. If a Berlin engineer pushes code at 6pm, a San Francisco engineer reviews at 8am next day.

By that time, the Berlin engineer is asleep. They can’t fix linting issues immediately. Code sits in review limbo.

Solution: Run linting locally before pushing. Pre-commit hooks enforce this. By the time code reaches review, formatting is correct. Reviews focus on logic.

Onboarding: New Developer Environment

A new developer clones the repo. They run a test and fail unexpectedly.

Why? Their environment is different (Node version 16 vs 18, Python 3.9 vs 3.11).

Solution: Include setup documentation:

### Step 10: Development Setup

1. Clone repo: `git clone ...`
2. Install dependencies: `npm install` or `pip install -r requirements.txt`
3. Install pre-commit hooks: `pre-commit install`
4. Run tests: `npm test` or `pytest`
5. Make a test commit to verify linting works

All team members use identical tools: Node LTS, Python 3.11, pre-commit v3.3.

Include a Makefile or justfile with common commands:

.PHONY: setup lint format test

setup:
	pip install -r requirements.txt
	npm install
	pre-commit install

lint:
	flake8 .
	npm run lint

format:
	black .
	prettier --write .

test:
	pytest
	npm test

New developers run make setup once. Everything is configured.

Exceptions: When Rules Don’t Apply

Sometimes a rule is wrong for a specific file. Example: a test file uses assert (normally flagged by some linters as bad practice).

Add rule exceptions:

Python (in the file):

# flake8: noqa
# This file tests internal implementation, needs lower-level assertions
import internal_module

JavaScript (in the file):

// eslint-disable-next-line no-console
console.log('Debug output for testing');

But exceptions are red flags in code review. If you need to disable a rule, question why. Is the rule wrong? Should the code be refactored? Are you using the right file for this case?

Distribute exceptions sparingly.

Step 11: Code Review Guidelines

Code review should not mention style. Pre-commit + CI handle all style.

Code review focuses on:

This is what humans should discuss. Style is for machines.

Step 12: Remote Team Success Metrics

After 2 weeks of enforcement:

  1. Commit success rate: Percentage of commits that pass linting on first try. Target: >95%.
  2. CI failures: Percentage of PRs that fail CI. Target: <5%.
  3. Review style comments: Number of code review comments about indentation, naming, formatting. Target: 0.
  4. Developer satisfaction: Is linting helping or annoying? Measure with surveys. Target: >4/5.
  5. Onboarding time: Time for new developer to make first approved PR. Target: <1 week.

If CI passes at 95% and code reviews have zero style comments, you’ve achieved enforcement.

Step 13: Recommendation Matrix

Use EditorConfig + Prettier + ESLint for JavaScript teams:

Use EditorConfig + Black + Flake8 for Python teams:

Use pre-commit hooks for all teams:

Invest in onboarding documentation:

Troubleshooting

Configuration changes not taking effect

Restart the relevant service or application after making changes. Some settings require a full system reboot. Verify the configuration file path is correct and the syntax is valid.

Permission denied errors

Run the command with sudo for system-level operations, or check that your user account has the necessary permissions. On macOS, you may need to grant terminal access in System Settings > Privacy & Security.

Connection or network-related failures

Check your internet connection and firewall settings. If using a VPN, try disconnecting temporarily to isolate the issue. Verify that the target server or service is accessible from your network.

Frequently Asked Questions

How long does it take to set up remote team code standards enforcement (2026)?

For a straightforward setup, expect 30 minutes to 2 hours depending on your familiarity with the tools involved. Complex configurations with custom requirements may take longer. Having your credentials and environment ready before starting saves significant time.

What are the most common mistakes to avoid?

The most frequent issues are skipping prerequisite steps, using outdated package versions, and not reading error messages carefully. Follow the steps in order, verify each one works before moving on, and check the official documentation if something behaves unexpectedly.

Do I need prior experience to follow this guide?

Basic familiarity with the relevant tools and command line is helpful but not strictly required. Each step is explained with context. If you get stuck, the official documentation for each tool covers fundamentals that may fill in knowledge gaps.

Can I adapt this for a different tech stack?

Yes, the underlying concepts transfer to other stacks, though the specific implementation details will differ. Look for equivalent libraries and patterns in your target stack. The architecture and workflow design remain similar even when the syntax changes.

Where can I get help if I run into issues?

Start with the official documentation for each tool mentioned. Stack Overflow and GitHub Issues are good next steps for specific error messages. Community forums and Discord servers for the relevant tools often have active members who can help with setup problems.