Guide for AI agents
This Agents.md file provides comprehensive guidance for OpenAI Codex and other AI agents working with this codebase.
Project Structure for OpenAI Codex Navigation
/services: Source code for various services/api: Backend API service implemented using FastAPI, SQLModel/src: Backend source code/tests: Backend test suite
/app: Frontend service implemented using Svelte/docio: Document parsing service
/clients: SDK/python: Python SDK/typescript: TS SDK
/docker: Docker files
Coding Conventions
General Conventions
- Follow the existing code style in each file
- Use meaningful variable and function names
- Add comments for complex logic
Backend Conventions
- Data models:
- DB models or classes live in
services/api/src/owl/db/models(implemented using SQLModel) - All SQL tables should have the same name and capitalisation as its corresponding DB class, and under
jamaischema - Each DB class will have a corresponding Pydantic class with name ending with underscore, for example
OrganizationandOrganization_. This provides a separation between the database schema model (SQLModel, does not validate input) and the API data transfer object (Pydantic model, validates inputs, suitable for API boundaries). - Pydantic models are imported from
clients/python/src/jamaibase/types/*viajamaibase.types, with some overridden inservices/api/src/owl/types/*jamaibase/types/*contains all classesowl/types/*additionally inject attributes, methods, validations that are useful only for backend
- DB models or classes live in
- For CRUD endpoints:
- Strongly prefer Query parameter over Path parameters for REST API
- Implement
FooUpdate,FooCreate,Foo_,FooReadPydantic models for input and output validation FooUpdatemodels should contain only fields that can be updated by the user (usually fields that are not primary key)- If an endpoint or function involves long external network calls (long execution time), avoid using FastAPI dependency injection (
session: Annotated[AsyncSession, Depends(yield_async_session)]) to provide DBsession, instead manually create a session using eitherasync with async_session() as sessionorwith sync_session() as session
- Pydantic tips:
- Prefer
field_validatorovermodel_validator, especially when usingmode="before".
- Prefer
- Always prefer single SQL statement over multi-step statements or Python loops whenever possible, for example:
- Avoid:
async with async_session() as session: secrets_dict = {} project = await session.get(Project, project_id) if project is None: return secrets_dict # Fetch all secrets secrets = (await session.exec(select(Secret))).all() # Filter secrets to only those belonging to the same organization secrets = [s for s in secrets if s.organization_id == project.organization_id] for secret in secrets: # Check if secret is accessible to this project # - allowed_projects == None means all projects are allowed # - allowed_projects == [] means no projects are allowed # - allowed_projects == ["proj1"] means only specific projects are allowed if secret.allowed_projects is None: # Secret is accessible to all projects decrypted_value = decrypt(secret.value, ENV_CONFIG.encryption_key_plain) secrets_dict[secret.name] = decrypted_value elif secret.allowed_projects is not None and project_id in secret.allowed_projects: # Check if this project is in the allowed list decrypted_value = decrypt(secret.value, ENV_CONFIG.encryption_key_plain) secrets_dict[secret.name] = decrypted_value - Good:
async with async_session() as session: # Single query using JOIN and filtering statement = ( select(Secret) .join(Project, Secret.organization_id == Project.organization_id) .where( Project.id == project_id, or_( Secret.allowed_projects.is_(None), Secret.allowed_projects.contains([project_id]), ), ) ) secrets = (await session.exec(statement)).all() # Assemble using a dictionary comprehension secrets_dict = { secret.name: decrypt(secret.value, ENV_CONFIG.encryption_key_plain) for secret in secrets }
- Avoid:
Pull Request Review Guidelines
- Always prioritise any security issues
- Always provide solution or suggestions for any issues found
- Check whether the code aligns with Coding Conventions stated in
Agents.md