- Python 3.12+
- pip or uv
# Clone the repository
git clone <repo-url> && cd insights
# Install with dev dependencies
pip install -e ".[dev]"
# Set up pre-commit hooks
pre-commit install
# Initialize the database
alembic upgrade headWe use ruff for linting and formatting:
ruff check . # Lint
ruff check . --fix # Lint with auto-fix
ruff format . # Format
ruff format --check . # Check formattingConfiguration is in pyproject.toml. Key settings:
- Line length: 100
- Target: Python 3.12
- Rules: E, W, F, I, N, UP, B, A, S, T20, SIM, TCH, RUF
We use bandit for security scanning:
bandit -r src/ -c pyproject.tomlUse SQLAlchemy 2.0 declarative style:
class MyModel(Base):
__tablename__ = "my_models"
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
name: Mapped[str] = mapped_column(String(255))
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())Use Pydantic v2 with model_config:
class MyResponse(BaseModel):
id: str
name: str
created_at: datetime
model_config = {"from_attributes": True}All configuration uses pydantic-settings with the PRIMER_ env prefix. See src/primer/common/config.py.
Use Depends() for auth and DB sessions:
@router.get("/api/v1/resource")
def list_resources(
admin: str = Depends(require_admin),
db: Session = Depends(get_db),
):
...src/primer/
├── common/ # Shared: models, schemas, config, database
├── server/
│ ├── app.py # FastAPI app factory
│ ├── deps.py # Auth dependencies
│ ├── routers/ # API endpoints
│ └── services/ # Business logic
├── hook/ # Claude Code SessionEnd hook
└── mcp/ # MCP sidecar server
tests/ # pytest test suite
scripts/ # Dev utilities
alembic/ # Database migrations
pytest -v # Run all tests
pytest -v --cov=primer --cov-report=term-missing # With coverage
pytest tests/test_ingest.py -v # Single file
pytest tests/test_analytics.py::test_overview -v # Single test- Use the
clientfixture fromconftest.pyfor API tests (FastAPITestClient) - Use
db_sessionfor direct database tests (auto-rollback per test) - Use
admin_headersfor endpoints requiring admin auth - Use
engineer_with_keyto get an engineer and raw API key for ingest tests - Tests run against SQLite in-memory — no external database required
def test_create_team(client, admin_headers):
resp = client.post("/api/v1/teams", json={"name": "Backend"}, headers=admin_headers)
assert resp.status_code == 200
assert resp.json()["name"] == "Backend"- Branch from
main - Make your changes following the coding standards above
- Add or update tests for any new functionality
- Ensure all checks pass:
ruff check . ruff format --check . bandit -r src/ -c pyproject.toml pytest -v
- Open a PR with a clear description of what changed and why
- Update documentation if adding endpoints, models, or configuration
# After modifying models in src/primer/common/models.py
alembic revision --autogenerate -m "add projects table"Always review the generated file in alembic/versions/:
- Verify
upgrade()creates the correct tables/columns - Verify
downgrade()reverses everything cleanly - Check for data-loss operations (column drops, type changes)
alembic upgrade head # Apply all pending migrations
alembic downgrade -1 # Roll back one migration
alembic current # Show current revision
alembic history # Show migration history