# Code Quality Standards
The robotics-webapp follows strict code quality standards to ensure maintainability, readability, and consistency.
## Python Backend Standards
### Linting with Ruff
All Python code in `backend/` must pass `ruff check`:
```powershell
cd backend
ruff check .
```
### Formatting with Ruff
Code is automatically formatted with `ruff format`:
```powershell
cd backend
ruff format .
```
### Running Both
```powershell
cd backend
ruff check --fix . # Auto-fix issues
ruff format . # Format code
```
## Code Style Guidelines
### Type Annotations
Use modern Python type annotations:
```python
# ✅ CORRECT - Modern syntax
def get_models() -> dict[str, Any]:
return {}
def find_path(app_id: str) -> str | None:
return None
# ❌ WRONG - Deprecated syntax
def get_models() -> Dict[str, Any]:
return {}
def find_path(app_id: str) -> Optional[str]:
return None
```
### Exception Handling
Always use exception chaining:
```python
# ✅ CORRECT
try:
result = await mcp_client.call_tool(...)
except Exception as e:
logger.error(f"Error: {e}")
raise HTTPException(status_code=500, detail=str(e)) from e
# ❌ WRONG
try:
result = await mcp_client.call_tool(...)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
```
### Import Organization
Imports are automatically sorted by ruff:
```python
# Standard library imports
import asyncio
import logging
import os
# Third-party imports
import aiohttp
from fastapi import FastAPI
# Local imports
from backend.mcp_client import mcp_client
```
### String Formatting
Use f-strings for string formatting:
```python
# ✅ CORRECT
logger.info(f"Loading model {model_id} on {provider}")
# ❌ WRONG
logger.info("Loading model {} on {}".format(model_id, provider))
```
### Blank Lines
- No whitespace on blank lines
- Two blank lines between top-level definitions
- One blank line between methods
### Variable Naming
- Use descriptive names
- Prefix unused variables with `_`:
```python
for _app_id, config in APP_CONFIGS.items():
# app_id not used
```
## TypeScript Frontend Standards
### Type Safety
- Use TypeScript types for all props and state
- Avoid `any` - use `unknown` or proper types
- Use interfaces for object shapes
### Component Structure
```typescript
// ✅ CORRECT - Proper structure
interface Props {
modelId: string
onLoad: (id: string) => void
}
export default function ModelCard({ modelId, onLoad }: Props) {
const [loading, setLoading] = useState(false)
const handleLoad = useCallback(async () => {
setLoading(true)
try {
await onLoad(modelId)
} finally {
setLoading(false)
}
}, [modelId, onLoad])
return (
// JSX
)
}
```
### Error Handling
```typescript
// ✅ CORRECT - Proper error handling
try {
const result = await llmService.loadModel(modelId)
if (result.success) {
// Handle success
} else {
alert(`Failed: ${result.error}`)
}
} catch (error) {
console.error('Error loading model:', error)
alert(`Error: ${error}`)
}
```
## Pre-commit Checks
Before committing, ensure:
1. **Python code passes ruff:**
```powershell
cd backend
ruff check .
ruff format .
```
2. **TypeScript compiles:**
```powershell
npm run build
```
3. **No console errors:**
- Check browser console
- Check backend logs
## Common Issues and Fixes
### Ruff Errors
| Error | Fix |
|-------|-----|
| `UP006` - Use `dict` instead of `Dict` | Replace `Dict[str, Any]` with `dict[str, Any]` |
| `UP045` - Use `X \| None` | Replace `Optional[str]` with `str \| None` |
| `B904` - Exception chaining | Add `from e` to raise statements |
| `W293` - Blank line whitespace | Remove whitespace from blank lines |
| `I001` - Import sorting | Run `ruff check --fix` |
### TypeScript Errors
| Error | Fix |
|-------|-----|
| `any` type | Use proper types or `unknown` |
| Missing props | Add to interface |
| Unused variables | Remove or prefix with `_` |
## Continuous Integration
The repository should include:
- **Ruff linting** in CI pipeline
- **TypeScript type checking** in CI pipeline
- **Automated formatting** checks
## Code Review Checklist
When reviewing code:
- [ ] Python code passes `ruff check`
- [ ] Python code formatted with `ruff format`
- [ ] TypeScript types are correct
- [ ] Error handling is proper
- [ ] No console errors
- [ ] No unused imports/variables
- [ ] Exception chaining used (`from e`)
- [ ] Modern type annotations (`dict` not `Dict`, `X | None` not `Optional[X]`)
## Tools
### Required Tools
- **Ruff** (Python linter/formatter)
- **TypeScript** (type checking)
- **ESLint** (optional, for additional TS checks)
### Installation
```powershell
# Install ruff
pip install ruff
# Verify installation
ruff --version
```
## Examples
### Good Python Code
```python
async def load_model(
self, model_id: str, provider: str = "ollama"
) -> dict[str, Any]:
"""Load a model for inference"""
try:
result = await mcp_client.call_tool(
'local_llm',
'llm_models',
{'operation': f'{provider}_load', 'model_id': model_id}
)
if result.get('success'):
self.active_models[model_id] = {
'model_id': model_id,
'provider': provider,
'loaded_at': datetime.now().isoformat(),
'status': 'loaded'
}
return {'success': True, 'model_id': model_id}
return {'success': False, 'error': result.get('error')}
except Exception as e:
logger.error(f"Error loading model {model_id}: {e}")
return {'success': False, 'error': str(e)}
```
### Good TypeScript Code
```typescript
interface ModelCardProps {
model: LLMModel
onLoad: (id: string, provider: string) => Promise<void>
onUnload: (id: string, provider: string) => Promise<void>
}
export default function ModelCard({
model,
onLoad,
onUnload
}: ModelCardProps) {
const [loading, setLoading] = useState(false)
const handleLoad = useCallback(async () => {
setLoading(true)
try {
await onLoad(model.id, model.provider)
} catch (error) {
console.error('Failed to load model:', error)
} finally {
setLoading(false)
}
}, [model.id, model.provider, onLoad])
return (
// Component JSX
)
}
```
## Resources
- [Ruff Documentation](https://docs.astral.sh/ruff/)
- [Python Type Hints](https://docs.python.org/3/library/typing.html)
- [TypeScript Handbook](https://www.typescriptlang.org/docs/)