quality-gates
Centralized quality gate execution for backend, frontend, and fullstack projects. Use when running format, lint, typecheck, or tests. Auto-detects stack and runs appropriate commands. Does NOT commit - calling command uses git-workflow skill.
When & Why to Use This Skill
Quality Gates is a centralized execution engine designed to enforce code standards across backend, frontend, and fullstack projects. It streamlines the development lifecycle by automating essential quality checks, including code formatting, linting, type checking, and unit testing. By intelligently auto-detecting the project stack (supporting Python/Ruff and Node/NPM), it serves as a single source of truth for code validation, ensuring consistency across all agentic workflows and preventing the introduction of technical debt.
Use Cases
- Automated Code Styling: Automatically run formatters like Ruff or Prettier to maintain a consistent codebase and resolve style inconsistencies without manual effort.
- Pre-Commit Validation: Execute linting and type-checking gates to catch syntax errors and type mismatches before code is committed to the repository.
- Fullstack Workflow Orchestration: Seamlessly manage quality checks in complex projects by letting the skill auto-detect whether to apply backend (Python) or frontend (JavaScript/TypeScript) validation rules.
- Regression Testing: Run comprehensive test suites (Pytest/NPM test) to ensure that new changes do not break existing functionality, providing immediate feedback on code integrity.
- CI/CD Mirroring: Use the skill to simulate remote pipeline checks locally, allowing developers to fix quality issues early in the development cycle.
| name | Quality Gates |
|---|---|
| description | Centralized quality gate execution for backend, frontend, and fullstack projects. Use when running format, lint, typecheck, or tests. Auto-detects stack and runs appropriate commands. Does NOT commit - calling command uses git-workflow skill. |
Quality Gates Skill
Centralized quality validation for tempo-demo workflows.
Purpose
Provide consistent quality gate execution:
- Auto-detect stack (backend/frontend/fullstack)
- Run appropriate commands per stack
- Return status for calling command to handle
- Does NOT commit (calling command uses git-workflow skill)
Core Responsibility
This skill is the single source of truth for quality gate execution. Commands should use this skill's functions rather than calling quality commands directly. This guarantees:
- ✅ Consistent execution across all workflows
- ✅ Proper stack detection and command routing
- ✅ Standardized return formats
- ✅ Separation of concerns (gates vs commits)
Functions
1. detect_stack()
Purpose: Determine if backend, frontend, or fullstack based on context
Usage:
Use quality-gates skill to detect stack
Implementation:
# Priority 1: Check .env PROJECT_STACK variable
if [ -f .env ]; then
source .env 2>/dev/null
if [ -n "$PROJECT_STACK" ]; then
echo "$PROJECT_STACK"
return
fi
fi
# Priority 2: Detect from current directory
CURRENT_DIR=$(pwd)
if [[ "$CURRENT_DIR" == *"/application/backend"* ]]; then
echo "backend"
return
elif [[ "$CURRENT_DIR" == *"/application/frontend"* ]]; then
echo "frontend"
return
fi
# Priority 3: Check for both backend and frontend existence
BACKEND_EXISTS=false
FRONTEND_EXISTS=false
if [ -f "application/backend/pyproject.toml" ]; then
BACKEND_EXISTS=true
fi
if [ -f "application/frontend/package.json" ]; then
FRONTEND_EXISTS=true
fi
if [ "$BACKEND_EXISTS" = true ] && [ "$FRONTEND_EXISTS" = true ]; then
echo "fullstack"
elif [ "$BACKEND_EXISTS" = true ]; then
echo "backend"
elif [ "$FRONTEND_EXISTS" = true ]; then
echo "frontend"
else
echo "unknown"
fi
Returns:
backend- Backend-only workfrontend- Frontend-only workfullstack- Both stacks presentunknown- Cannot determine
2. run_format()
Purpose: Auto-format code, return whether changes were made
Usage:
Use quality-gates skill to run format
Implementation:
# Detect stack first
STACK=$(detect_stack)
case "$STACK" in
backend)
cd application/backend || exit 1
# Capture files before formatting
BEFORE=$(git diff --name-only | sort)
# Run format
uv run ruff format .
# Check if changes were made
AFTER=$(git diff --name-only | sort)
if [ "$BEFORE" != "$AFTER" ] || [ -n "$(git diff)" ]; then
echo "CHANGES_MADE"
return 0
else
echo "NO_CHANGES"
return 0
fi
;;
frontend)
cd application/frontend || exit 1
# Capture files before formatting
BEFORE=$(git diff --name-only | sort)
# Run format
npm run format
# Check if changes were made
AFTER=$(git diff --name-only | sort)
if [ "$BEFORE" != "$AFTER" ] || [ -n "$(git diff)" ]; then
echo "CHANGES_MADE"
return 0
else
echo "NO_CHANGES"
return 0
fi
;;
fullstack)
# Run both, aggregate results
BACKEND_RESULT="NO_CHANGES"
FRONTEND_RESULT="NO_CHANGES"
# Backend
if [ -f "application/backend/pyproject.toml" ]; then
cd application/backend || exit 1
BEFORE=$(git diff --name-only | sort)
uv run ruff format .
AFTER=$(git diff --name-only | sort)
if [ "$BEFORE" != "$AFTER" ] || [ -n "$(git diff)" ]; then
BACKEND_RESULT="CHANGES_MADE"
fi
cd ../..
fi
# Frontend
if [ -f "application/frontend/package.json" ]; then
cd application/frontend || exit 1
BEFORE=$(git diff --name-only | sort)
npm run format
AFTER=$(git diff --name-only | sort)
if [ "$BEFORE" != "$AFTER" ] || [ -n "$(git diff)" ]; then
FRONTEND_RESULT="CHANGES_MADE"
fi
cd ../..
fi
# Determine overall result
if [ "$BACKEND_RESULT" = "CHANGES_MADE" ] || [ "$FRONTEND_RESULT" = "CHANGES_MADE" ]; then
echo "CHANGES_MADE"
else
echo "NO_CHANGES"
fi
return 0
;;
*)
echo "ERROR: Unknown stack"
return 1
;;
esac
Returns:
CHANGES_MADE- Files were modified by formattingNO_CHANGES- No formatting changes neededERROR: {message}- Execution failed
Calling Command Responsibility:
If CHANGES_MADE, use git-workflow skill to commit:
Use git-workflow skill to commit changes:
- Type: style
- Scope: (empty)
- Message: auto-format code
- Issue: {ISSUE_ID}
3. run_lint()
Purpose: Lint code with auto-fix where possible
Usage:
Use quality-gates skill to run lint
Implementation:
# Detect stack first
STACK=$(detect_stack)
case "$STACK" in
backend)
cd application/backend || exit 1
# Capture files before linting
BEFORE=$(git diff --name-only | sort)
# Run lint with auto-fix
if uv run ruff check --fix .; then
# Check if changes were made
AFTER=$(git diff --name-only | sort)
if [ "$BEFORE" != "$AFTER" ] || [ -n "$(git diff)" ]; then
echo "CHANGES_MADE"
return 0
else
echo "PASSED"
return 0
fi
else
# Lint failed - capture errors
echo "FAILED"
return 1
fi
;;
frontend)
cd application/frontend || exit 1
# Capture files before linting
BEFORE=$(git diff --name-only | sort)
# Run lint
if npm run lint; then
# Check if changes were made
AFTER=$(git diff --name-only | sort)
if [ "$BEFORE" != "$AFTER" ] || [ -n "$(git diff)" ]; then
echo "CHANGES_MADE"
return 0
else
echo "PASSED"
return 0
fi
else
echo "FAILED"
return 1
fi
;;
fullstack)
# Run both, aggregate results
BACKEND_RESULT="PASSED"
FRONTEND_RESULT="PASSED"
OVERALL_EXIT=0
# Backend
if [ -f "application/backend/pyproject.toml" ]; then
cd application/backend || exit 1
BEFORE=$(git diff --name-only | sort)
if uv run ruff check --fix .; then
AFTER=$(git diff --name-only | sort)
if [ "$BEFORE" != "$AFTER" ] || [ -n "$(git diff)" ]; then
BACKEND_RESULT="CHANGES_MADE"
fi
else
BACKEND_RESULT="FAILED"
OVERALL_EXIT=1
fi
cd ../..
fi
# Frontend
if [ -f "application/frontend/package.json" ]; then
cd application/frontend || exit 1
BEFORE=$(git diff --name-only | sort)
if npm run lint; then
AFTER=$(git diff --name-only | sort)
if [ "$BEFORE" != "$AFTER" ] || [ -n "$(git diff)" ]; then
FRONTEND_RESULT="CHANGES_MADE"
fi
else
FRONTEND_RESULT="FAILED"
OVERALL_EXIT=1
fi
cd ../..
fi
# Determine overall result
if [ "$OVERALL_EXIT" -ne 0 ]; then
echo "FAILED"
return 1
elif [ "$BACKEND_RESULT" = "CHANGES_MADE" ] || [ "$FRONTEND_RESULT" = "CHANGES_MADE" ]; then
echo "CHANGES_MADE"
return 0
else
echo "PASSED"
return 0
fi
;;
*)
echo "ERROR: Unknown stack"
return 1
;;
esac
Returns:
CHANGES_MADE- Auto-fixes were appliedPASSED- Lint passed with no changesFAILED- Lint errors that cannot be auto-fixedERROR: {message}- Execution failed
Calling Command Responsibility:
If CHANGES_MADE, use git-workflow skill to commit:
Use git-workflow skill to commit changes:
- Type: style
- Scope: (empty)
- Message: auto-fix lint issues
- Issue: {ISSUE_ID}
If FAILED, report errors and potentially fix manually.
4. run_typecheck()
Purpose: Type checking (reports errors, no auto-fix)
Usage:
Use quality-gates skill to run typecheck
Implementation:
# Detect stack first
STACK=$(detect_stack)
case "$STACK" in
backend)
cd application/backend || exit 1
# Run type check
if uv run mypy --strict .; then
echo "PASSED"
return 0
else
echo "FAILED"
return 1
fi
;;
frontend)
cd application/frontend || exit 1
# Run type check
if npm run type-check; then
echo "PASSED"
return 0
else
echo "FAILED"
return 1
fi
;;
fullstack)
# Run both, aggregate results
BACKEND_EXIT=0
FRONTEND_EXIT=0
# Backend
if [ -f "application/backend/pyproject.toml" ]; then
cd application/backend || exit 1
if ! uv run mypy --strict .; then
BACKEND_EXIT=1
fi
cd ../..
fi
# Frontend
if [ -f "application/frontend/package.json" ]; then
cd application/frontend || exit 1
if ! npm run type-check; then
FRONTEND_EXIT=1
fi
cd ../..
fi
# Determine overall result
if [ "$BACKEND_EXIT" -ne 0 ] || [ "$FRONTEND_EXIT" -ne 0 ]; then
echo "FAILED"
return 1
else
echo "PASSED"
return 0
fi
;;
*)
echo "ERROR: Unknown stack"
return 1
;;
esac
Returns:
PASSED- Type check passedFAILED- Type errors found (stderr contains details)ERROR: {message}- Execution failed
Note: Typecheck cannot auto-fix. Calling command should report errors and potentially attempt manual fixes.
5. run_tests()
Purpose: Run test suite
Usage:
Use quality-gates skill to run tests
Implementation:
# Detect stack first
STACK=$(detect_stack)
case "$STACK" in
backend)
cd application/backend || exit 1
# Run tests
if uv run pytest --cov --cov-report=term-missing; then
echo "PASSED"
return 0
else
echo "FAILED"
return 1
fi
;;
frontend)
cd application/frontend || exit 1
# Run tests
if npm test; then
echo "PASSED"
return 0
else
echo "FAILED"
return 1
fi
;;
fullstack)
# Run both, aggregate results
BACKEND_EXIT=0
FRONTEND_EXIT=0
# Backend
if [ -f "application/backend/pyproject.toml" ]; then
cd application/backend || exit 1
if ! uv run pytest --cov --cov-report=term-missing; then
BACKEND_EXIT=1
fi
cd ../..
fi
# Frontend
if [ -f "application/frontend/package.json" ]; then
cd application/frontend || exit 1
if ! npm test; then
FRONTEND_EXIT=1
fi
cd ../..
fi
# Determine overall result
if [ "$BACKEND_EXIT" -ne 0 ] || [ "$FRONTEND_EXIT" -ne 0 ]; then
echo "FAILED"
return 1
else
echo "PASSED"
return 0
fi
;;
*)
echo "ERROR: Unknown stack"
return 1
;;
esac
Returns:
PASSED- All tests passedFAILED- Test failures (stderr contains details)ERROR: {message}- Execution failed
Note: Tests cannot auto-fix. Calling command should report failures.
6. run_all()
Purpose: Run all gates in sequence
Usage:
Use quality-gates skill to run all gates
Implementation:
Run in order:
1. Use quality-gates skill to run format
- If CHANGES_MADE: Calling command should commit via git-workflow
2. Use quality-gates skill to run lint
- If CHANGES_MADE: Calling command should commit via git-workflow
3. Use quality-gates skill to run typecheck
- If FAILED: Report errors
4. Use quality-gates skill to run tests
- If FAILED: Report failures
Return: Overall pass/fail status based on all gates
Returns:
ALL_PASSED- All gates passed (format and lint may have made changes that were committed)SOME_FAILED- One or more gates failedERROR: {message}- Execution failed
Note: This is a meta-function that orchestrates the other functions. The calling command is responsible for:
- Committing format/lint changes via git-workflow skill
- Handling typecheck/test failures
- Potentially re-running after fixes
Usage in Commands
Pattern: /implement
## Quality Gate Execution
1. Use quality-gates skill to run format
- If CHANGES_MADE:
Use git-workflow skill to commit changes:
- Type: style
- Scope: (empty)
- Message: auto-format code
- Issue: {ISSUE_ID}
2. Use quality-gates skill to run lint
- If CHANGES_MADE:
Use git-workflow skill to commit changes:
- Type: style
- Scope: (empty)
- Message: auto-fix lint issues
- Issue: {ISSUE_ID}
- If FAILED: Report errors, potentially fix
3. Use quality-gates skill to run typecheck
- If FAILED: Report errors, potentially fix
4. Use quality-gates skill to run tests
- If FAILED: Report failures
Pattern: /test
## Quality Gate Validation
Use quality-gates skill to run all gates
Handle results:
- Format/Lint CHANGES_MADE: Commit via git-workflow
- Typecheck/Test FAILED: Report and loop until fixed
Stack Detection Logic
Priority 1: .env Variable
Check for PROJECT_STACK variable in .env:
PROJECT_STACK=backend # Forces backend
PROJECT_STACK=frontend # Forces frontend
PROJECT_STACK=fullstack # Forces fullstack
Priority 2: Current Directory
Detect from current working directory:
- In
application/backend/→ backend - In
application/frontend/→ frontend
Priority 3: Project Structure
Check for existence of both stacks:
- Both
application/backend/pyproject.tomlANDapplication/frontend/package.json→ fullstack - Only
application/backend/pyproject.toml→ backend - Only
application/frontend/package.json→ frontend
Gate Commands by Stack
Backend Gates
Working Directory: application/backend/
Format:
uv run ruff format .- Auto-fixes: Yes
- Can commit: Yes
Lint:
uv run ruff check --fix .- Auto-fixes: Partial (safe fixes only)
- Can commit: Yes (if changes made)
Typecheck:
uv run mypy --strict .- Auto-fixes: No
- Can commit: No
Tests:
uv run pytest --cov --cov-report=term-missing- Auto-fixes: No
- Can commit: No
Frontend Gates
Working Directory: application/frontend/
Format:
npm run format- Auto-fixes: Yes
- Can commit: Yes
Lint:
npm run lint- Auto-fixes: Partial
- Can commit: Yes (if changes made)
Typecheck:
npm run type-check- Auto-fixes: No
- Can commit: No
Tests:
npm test- Auto-fixes: No
- Can commit: No
Fullstack Gates
Run both backend and frontend gates sequentially:
- Run backend gate
- Run frontend gate
- Aggregate results
Result Aggregation:
CHANGES_MADEif either stack has changesFAILEDif either stack failsPASSEDonly if both pass with no changes
Error Handling
Gate Execution Failures
If a gate command fails to execute:
- Capture stderr
- Return
ERROR: {message} - Calling command should handle and potentially abort
Stack Detection Failures
If stack cannot be determined:
- Return
ERROR: Unknown stack - Suggest:
- Add
PROJECT_STACK=backend|frontend|fullstackto.env - Or run from correct directory
- Or check project structure
- Add
Missing Dependencies
If required tools are missing:
- Backend:
uvnot installed - Frontend:
npmnot installed - Return
ERROR: Missing dependency: {tool} - Suggest installation instructions
Best Practices
- Always detect stack first - Never assume stack type
- Run gates in order - Format → Lint → Typecheck → Test
- Commit format/lint changes separately - Via git-workflow skill
- Don't commit typecheck/test fixes - Let developer fix properly
- Handle errors gracefully - Return clear status codes
- Aggregate results for fullstack - Report both stacks clearly
- Use absolute paths - When changing directories
- Capture git state - Before and after for change detection
Integration with Other Skills
With git-workflow Skill
Quality-gates skill detects changes, git-workflow skill commits them:
# Quality-gates skill
Use quality-gates skill to run format
# Returns: CHANGES_MADE
# Git-workflow skill
Use git-workflow skill to commit changes:
- Type: style
- Scope: (empty)
- Message: auto-format code
- Issue: TEMPO-123
Why Separate?
- Quality-gates focuses on execution and detection
- Git-workflow focuses on commit formatting and conventions
- Single responsibility principle
- Commands can choose when/how to commit
With task-patterns Skill
Quality-gates can be used before/after Linear operations:
# Before implementation
Use task-patterns skill to fetch issue TEMPO-123
Use quality-gates skill to run all gates # Ensure clean starting state
# After implementation
Use quality-gates skill to run all gates
Use task-patterns skill to comment on TEMPO-123 with gate results
Troubleshooting
Skill not detecting correct stack
Solution:
# Add to .env
PROJECT_STACK=backend # or frontend or fullstack
Format/lint not finding files
Solution:
- Ensure you're in project root
- Check that
application/backend/orapplication/frontend/exist - Verify
pyproject.tomlorpackage.jsonexist
Commands return "ERROR: Unknown stack"
Solution:
- Check directory structure
- Add
PROJECT_STACKto.env - Ensure at least one stack exists
Typecheck passes in skill but fails manually
Solution:
- Check that same command is being run
- Verify working directory
- Check for environment differences
Examples
Example 1: Backend Format with Commit
## Command: /implement TEMPO-123
1. Use quality-gates skill to detect stack
# Returns: backend
2. Use quality-gates skill to run format
# Returns: CHANGES_MADE
3. Use git-workflow skill to commit changes:
- Type: style
- Scope: (empty)
- Message: auto-format code
- Issue: TEMPO-123
# Commits format changes
Example 2: Fullstack All Gates
## Command: /test
1. Use quality-gates skill to run all gates
# Runs format, lint, typecheck, test for both backend and frontend
# Returns: SOME_FAILED (backend typecheck failed)
2. Report: Backend typecheck failed with 3 errors
- Fix type errors manually
- Re-run: Use quality-gates skill to run typecheck
# Returns: PASSED
3. Use quality-gates skill to run all gates
# Returns: ALL_PASSED
Example 3: Frontend Lint with Auto-Fix
## Command: /implement TEMPO-456
1. Use quality-gates skill to detect stack
# Returns: frontend
2. Use quality-gates skill to run lint
# Returns: CHANGES_MADE (auto-fixed unused imports)
3. Use git-workflow skill to commit changes:
- Type: style
- Scope: (empty)
- Message: auto-fix lint issues
- Issue: TEMPO-456
Testing the Skill
Manual Testing
# Test stack detection
STACK=$(detect_stack)
echo "Detected stack: $STACK"
# Test format (no commit)
RESULT=$(run_format)
echo "Format result: $RESULT"
# Test lint
RESULT=$(run_lint)
echo "Lint result: $RESULT"
# Test typecheck
RESULT=$(run_typecheck)
echo "Typecheck result: $RESULT"
# Test tests
RESULT=$(run_tests)
echo "Tests result: $RESULT"
Integration Testing
From a command:
Use quality-gates skill to run all gates
# Verify all gates execute correctly
# Verify correct stack is detected
# Verify results are properly returned
Future Enhancements
Potential additions (not required now):
- Custom Coverage Thresholds: Pass coverage minimum to run_tests()
- Parallel Execution: Run backend and frontend gates in parallel for fullstack
- Detailed Error Parsing: Return structured error objects
- Gate Timing: Report execution time per gate
- Selective Gate Execution: Run only specific gates
- Watch Mode: Continuous gate execution on file changes
Ready to use! This skill provides consistent quality validation across all tempo-demo workflows.