Codered-Vigneshvar

Ojas Engineering Skill

Prefer the simplest thing that satisfies the invariants. Ask before introducing a new dependency, a new service, or a new database.

Codered-Vigneshvar 0 Updated 2w ago

Resources

6
GitHub

Install

npx skillscat add codered-vigneshvar/ojas

Install via the SkillsCat registry.

SKILL.md

Ojas Engineering Skill

This file is read first by any AI agent working in this repo. Follow it strictly.

Product context

Ojas is an AI-native patient workspace. A doctor opens a patient profile, dumps in reports/audio/prescriptions/lab results/handwritten notes, and asks anything. The AI extracts, stores, and retrieves patient information with mandatory source citations. Per-patient scoping is a hard invariant — the AI assistant must only see one patient's data at a time. Cross-patient queries go through a separate structured layer.

Hard invariants (never violate)

  1. Per-patient scoping at the query level. Every vector or relational query that feeds the AI MUST filter by patient_id in the SQL WHERE clause, not in application code, not in post-processing.
  2. Every AI-surfaced fact must have a source_artifact_id. Citations are non-negotiable. If a fact can't be cited, it shouldn't be displayed as a fact — show it as raw context.
  3. Audit log every AI query and every data access. Use core/audit.py. No exceptions.
  4. Patient data never leaves India in prod. All cloud services must be in an Indian region. Local LLM in dev. Cloud LLMs only behind an explicit env flag (ALLOW_CLOUD_LLM=true).
  5. Consent must exist before any AI processing. Check consents table before invoking LLMs on a patient's data.
  6. Never log raw patient data. Logs may include IDs and metadata, never PHI.

Architecture rules

  • Layered: routes (thin) → services (business logic) → repositories (data access) → models (ORM).
  • Routes are thin. No business logic in route handlers. They parse input, call a service, return a response.
  • Services are pure-ish. They take typed inputs and return typed outputs. They don't reach into request objects.
  • Repositories own SQL. No SQL in services. No SQLAlchemy in routes.
  • LLM, STT, storage are behind interfaces. Never import vllm or boto3 directly in service code. Use llm.base.LLMClient, stt.base.STTClient, storage.base.ObjectStorage.

Code conventions

  • Python: ruff format, strict mypy, async-first for I/O. Type everything. No Any without a comment explaining why.
  • TypeScript: strict mode, no any. Components are function components with hooks. Server state in TanStack Query, client state in Zustand.
  • Imports: absolute imports in Python (from ojas.services...), absolute in TS via @/ alias.
  • Naming: snake_case Python, camelCase TS, PascalCase components and types, SCREAMING_SNAKE for constants.
  • File size: if a file exceeds ~300 lines, consider splitting.
  • No premature abstraction. Inline first, extract on second use.

Data model rules

  • Every table has id, created_at, updated_at.
  • Every patient-scoped table has patient_id with a FK and an index.
  • Every extracted entity (medications, diagnoses, etc.) has source_artifact_id FK.
  • Use JSONB for long-tail extracted fields, typed columns for everything queried relationally.
  • Migrations only via Alembic. Never edit schemas by hand. One concern per migration.

Prompts

  • Prompts live in apps/api/src/ojas/llm/prompts/ as versioned files (e.g. extract_medications_v3.txt).
  • Never inline prompts in service code longer than 3 lines.
  • Every prompt has a header describing inputs, outputs, and the eval cases that cover it.

Testing rules

  • Every service method has a unit test.
  • Every route has at least one integration test against a real test DB.
  • AI behavior is tested through the evals harness, not unit tests. Mock LLMs in unit tests.
  • make test must pass before any commit.

Eval rules

  • Any change to a prompt, model, retrieval logic, or extraction pipeline requires re-running make evals.
  • New features add new eval cases.
  • Eval failures block merges.

Tech stack (do not change without an ADR)

  • Postgres 16 + pgvector (no MongoDB, no separate vector DB)
  • FastAPI + SQLAlchemy 2.0 async + Alembic + Pydantic v2
  • React + Vite + TS + TanStack Query + Zustand + shadcn/ui
  • Redis + Arq for background jobs
  • MinIO local, S3-compatible interface
  • vLLM serving Qwen2.5 in dev; cloud LLMs behind ALLOW_CLOUD_LLM env flag
  • Langfuse for LLM tracing
  • uv for Python packages, pnpm for Node packages

Git and commit rules

  • Never add Claude as a co-author. Do not include Co-Authored-By: Claude or any Anthropic AI attribution in commit messages.
  • Commit messages should describe the why, not the what.
  • Stage specific files — never git add . or git add -A.
  • Never skip hooks (--no-verify) without explicit instruction.
  • Never force-push to main.

When making changes

  1. Read this file first.
  2. Read the relevant docs/decisions/*.md if your change touches architecture.
  3. If you're introducing a new pattern, write an ADR in docs/decisions/.
  4. Update docs alongside code changes.
  5. Update this file if you discover a convention worth encoding.

When unsure

Prefer the simplest thing that satisfies the invariants. Ask before introducing a new dependency, a new service, or a new database.