Monorepo with Python backend (./python/) and React/TypeScript frontend (./frontend/).
- Package manager:
uv, Python >=3.12, virtual env at./python/.venv - Commands (from root):
make format,make lint,make test - Run single test:
uv run pytest path/to/test.py::test_functionoruv run pytest path/to/test.py::TestClassName::test_method - Run tests with keyword:
uv run pytest ./python -k "test_create_plan"
- Linting/formatting: Use
ruff(line length 88, target py312),ruff format+isort - Imports: Avoid inline imports unless for circular deps. Import >3 names? Use qualified imports:
import pathlib; pathlib.Path. UseTYPE_CHECKINGfor type hints.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from mypkg.schemas import AgentConfig- Runtime checks: Avoid excessive
getattr/hasattr. For pydanticBaseModel, prefer validated attributes/type annotations. Use Protocols/TypedDict for structural typing. Make runtime checks explicit, minimal, well-documented. - Async-first: Prefer async APIs for I/O. Use
httpxfor HTTP,asyncio/anyiofor async. Ensure clear async boundaries: public APIs and I/O paths should be async. Provide minimal sync adapters only when needed.
import asyncio
import httpx
async def fetch_state(url: str, timeout_s: float) -> dict:
async with httpx.AsyncClient(timeout=timeout_s) as client:
resp = await client.get(url)
resp.raise_for_status()
return resp.json()
def fetch_state_sync(url: str, timeout_s: float) -> dict:
"""Synchronous adapter. Prefer the async variant."""
return asyncio.run(fetch_state(url, timeout_s))- Logging: Use
loguruwith{}placeholders. Log key events at info. Avoid excessive logging. Do not log sensitive data.logger.warningfor recoverable issues,logger.exceptiononly for truly unexpected errors.
from loguru import logger
logger.info("Processing {count} items", count=count)
# Recoverable error
async def send_notification(msg: str) -> None:
try:
await notify_service(msg)
except NetworkError as exc:
logger.warning("Notification failed, continuing: {err}", err=str(exc))
# Unexpected error
async def critical_operation() -> None:
try:
await process_critical_data()
except Exception:
logger.exception("Critical operation failed unexpectedly")
raise- Type hints: Add to public/internal APIs. Comments/docstrings in English explaining why, not what. Use Protocols, TypedDict, pydantic models; avoid excessive literal dict access.
- Error handling: Max 2 levels try-except. Catch specific exceptions. Prefer guard clauses over broad exception use.
try:
data = json.loads(raw)
except json.JSONDecodeError as exc:
logger.info("Invalid JSON: {err}", err=str(exc))
return {}- Structure: Extract helpers at module level; avoid nested functions. Functions <200 lines. Max 10 parameters; prefer wrapping in struct/object. Separate concerns: I/O, parsing, business logic, orchestration.
- Strings/literals: Wrap lines <100 chars. Avoid long string literals. Centralize constants. Avoid magic numbers/strings.
DEFAULT_TIMEOUT_S: float = 10.0
MAX_RETRIES: int = 3- Boolean logic: Be careful with
orwhere 0, empty, or False may be meaningful. Prefer explicit checks:value if value is not None else default. - Module layout: Group agent core, adapters, utilities into separate modules. Keep public surface small. Delay re-exports in
__init__until stable. For circular deps, extract to shared interfaces/contracts module.
- Package manager:
bun, Node >=22, React Router v7, TypeScript strict mode - Commands:
bun run dev,bun run build,bun run typecheck,bun run lint,bun run check - Auto-fix:
bun run lint:fix,bun run format:fix,bun run check:fix
- Linting/formatting: Use
biome(configured inbiome.json). Double quotes. 2-space indentation. - Path aliases:
@/*→./src/*,@valuecell/*→./src/components/valuecell/* - Imports: Use
typekeyword for type-only imports. Biome auto-organizes imports.
import type { AgentInfo } from "@/types/agent";
import { useQuery } from "@tanstack/react-query";- Components:
.tsxextension, PascalCase naming. Prefer named exports. Usememowhen needed. Extract custom hooks tosrc/hooks/. Usecn()(clsx + tailwind-merge) for className composition.
export const StreamingIndicator = memo(() => {
return <div>...</div>;
});- State management: React Query (
@tanstack/react-query) for server state. Zustand for client state.mutativefor immutable updates.
const { data } = useQuery({
queryKey: ["conversations"],
queryFn: () => apiClient.get("/conversations/"),
});- API & data: Zod for runtime validation. Types in
src/types/.@tanstack/react-formfor forms. - Utilities:
.tsextension, camelCase naming. Place insrc/lib/or feature-specific directories.
- Python: Use
pytestwithpytest-asynciofor async tests. 90% coverage threshold enforced bydiff-cover. - Frontend: No test framework configured yet. When adding tests, check
package.jsonscripts andbiome.jsonrules.
- On push to main/PRs, GitHub Actions run:
- Python: ruff check, ruff format check, isort, pytest with coverage
- Frontend: biome checks, typecheck, build verification
- Ensure all checks pass before merging.
- Avoid inline imports unless for circular dependencies
- Prefer explicit checks:
value if value is not None else defaultovervalue or default - Centralize constants, avoid magic numbers/strings
- Keep public API surfaces small, delay
__init__re-exports - If circular dependencies appear, extract to shared interfaces/contracts module