Tooling and Pipelines Guidelines¶
The Prime Directive¶
Automate everything you do twice. No exceptions.
Principle 1: Tool Creation Rule¶
The Two-Time Rule¶
If you perform any verification, validation, or build task twice, you MUST create a script for it.
Why Scripts?¶
- Consistency across agents and developers
- Reproducibility
- Documentation through code
- Reduced human error
- Faster onboarding
Script Requirements¶
Every script must:
- Be executable (
chmod +x) - Have clear error messages
- Return appropriate exit codes
- Be documented in
scripts/README.md - Work in CI environment
Script Template¶
#!/bin/bash
# Script: [name]
# Purpose: [what it does]
# Usage: ./scripts/[name].sh [args]
set -e # Exit on error
set -u # Exit on undefined variable
# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
# Functions
log_info() {
echo "[INFO] $1"
}
log_error() {
echo "[ERROR] $1" >&2
}
# Main logic
main() {
log_info "Starting [task]..."
# Your code here
log_info "Completed successfully"
}
main "$@"
Principle 2: CI/CD Priority¶
Pipeline Priority Order¶
When setting up CI/CD, implement in this order:
- Lint - Fast feedback on code quality
- Build - Ensure code compiles/bundles
- Test - Verify functionality
- Coverage - Enforce quality gates
- Security - Scan for vulnerabilities
- Deploy - Only after all checks pass
GitHub Actions Structure¶
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
lint:
# First - fastest feedback
build:
# Second - ensure it compiles
needs: lint
test:
# Third - verify behavior
needs: build
security:
# Fourth - check for vulnerabilities
needs: test
deploy:
# Last - only after all checks
needs: [lint, build, test, security]
if: github.ref == 'refs/heads/main'
Required Checks¶
Every PR must pass:
- [ ] Linting (ESLint/Prettier for JS)
- [ ] Build succeeds
- [ ] Tests pass
- [ ] Coverage ≥ 90%
- [ ] No security vulnerabilities
- [ ] No merge conflicts
Principle 3: Standard Scripts¶
Required Scripts¶
Every project must have these scripts in scripts/:
validate.sh¶
Purpose: Run all validation checks locally (mirrors .github/workflows/ci.yml)
#!/bin/bash
# Run the deterministic quality gate (see scripts/validate.sh)
set -euo pipefail
npm run lint
npm run typecheck
npm run format:check
npm test # Vitest + 90% coverage floor
npm run build # Firefox MV2 (shipping)
npx web-ext lint --source-dir=.output/firefox-mv2
npm run build:mv3 # Firefox MV3 (capability artifact)
echo "All validations passed."
setup.sh¶
Purpose: Set up development environment
#!/bin/bash
# Set up development environment
set -e
echo "📦 Installing dependencies..."
npm install
echo "🔧 Setting up git hooks..."
npm run prepare
echo "✅ Setup complete!"
lint.sh¶
Purpose: Run linting with auto-fix option
#!/bin/bash
# Run linting
set -e
if [ "${1:-}" = "--fix" ]; then
npm run lint:fix
else
npm run lint
fi
Script Documentation¶
Maintain scripts/README.md:
# Scripts
## Available Scripts
| Script | Purpose | Usage |
| ----------- | --------------------- | --------------------------- |
| validate.sh | Run all checks | `./scripts/validate.sh` |
| setup.sh | Setup dev environment | `./scripts/setup.sh` |
| lint.sh | Run linter | `./scripts/lint.sh [--fix]` |
Principle 4: Tooling Standards¶
Required Development Tools¶
| Tool | Purpose | Configuration File |
|---|---|---|
| TypeScript | Strict type checks | tsconfig.json |
| ESLint | Lint (TS/JS) | .eslintrc.js |
| Prettier | Code formatting | .prettierrc |
| Vitest | Unit tests | vitest.config.ts |
| WXT | Extension build | wxt.config.ts |
| Husky | Git hooks | .husky/ |
Configuration Files¶
Keep all configuration in project root:
project/
├── .eslintrc.js
├── .prettierrc
├── tsconfig.json
├── vitest.config.ts
├── wxt.config.ts
├── package.json
└── scripts/
└── ...
Version Pinning¶
All tools must be version-pinned in package.json:
{
"devDependencies": {
"eslint": "^8.56.0",
"prettier": "^3.2.4",
"typescript": "5.9.3",
"vitest": "4.1.10",
"wxt": "0.20.27"
}
}
CI/CD Workflow Template¶
The repository's actual gate¶
The live pipeline is .github/workflows/ci.yml. Coverage is enforced by the thresholds in vitest.config.ts (not a separate script), and the project does not run CodeQL. Mirror that gate rather than the generic example above:
name: CI
on:
push:
branches: [main, master, rebuild]
pull_request:
branches: [main, master, rebuild]
workflow_dispatch:
permissions:
contents: read
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
- run: npm ci
- run: npm run typecheck
- run: npm run lint
- run: npm test # Vitest + 90% coverage floor
- run: npm run build # Firefox MV2 (shipping)
- run: npx web-ext lint --source-dir=.output/firefox-mv2
build-mv3:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
- run: npm ci
- run: npm run build:mv3 # Firefox MV3 (capability artifact)
The optional Selenium bench runs only on manual dispatch and is non-gating.
Summary¶
- Automate on second occurrence - Script everything repeatable
- CI/CD is mandatory - Typecheck → Lint → Test → Build (MV2 + MV3)
- Standard scripts - validate.sh, setup.sh, lint.sh
- Pin all versions - Reproducibility is key